annotate DEPENDENCIES/generic/include/boost/statechart/fifo_worker.hpp @ 133:4acb5d8d80b6 tip

Don't fail environmental check if README.md exists (but .txt and no-suffix don't)
author Chris Cannam
date Tue, 30 Jul 2019 12:25:44 +0100
parents 2665513ce2d3
children
rev   line source
Chris@16 1 #ifndef BOOST_STATECHART_FIFO_WORKER_HPP_INCLUDED
Chris@16 2 #define BOOST_STATECHART_FIFO_WORKER_HPP_INCLUDED
Chris@16 3 //////////////////////////////////////////////////////////////////////////////
Chris@16 4 // Copyright 2002-2008 Andreas Huber Doenni
Chris@16 5 // Distributed under the Boost Software License, Version 1.0. (See accompany-
Chris@16 6 // ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
Chris@16 7 //////////////////////////////////////////////////////////////////////////////
Chris@16 8
Chris@16 9
Chris@16 10
Chris@16 11 #include <boost/assert.hpp>
Chris@16 12 #include <boost/noncopyable.hpp>
Chris@16 13 #include <boost/function/function0.hpp>
Chris@16 14 #include <boost/bind.hpp>
Chris@16 15 // BOOST_HAS_THREADS, BOOST_MSVC
Chris@16 16 #include <boost/config.hpp>
Chris@16 17
Chris@16 18 #include <boost/detail/allocator_utilities.hpp>
Chris@16 19
Chris@16 20 #ifdef BOOST_HAS_THREADS
Chris@16 21 # ifdef BOOST_MSVC
Chris@16 22 # pragma warning( push )
Chris@16 23 // "conditional expression is constant" in basic_timed_mutex.hpp
Chris@16 24 # pragma warning( disable: 4127 )
Chris@16 25 // "conversion from 'int' to 'unsigned short'" in microsec_time_clock.hpp
Chris@16 26 # pragma warning( disable: 4244 )
Chris@16 27 // "... needs to have dll-interface to be used by clients of class ..."
Chris@16 28 # pragma warning( disable: 4251 )
Chris@16 29 // "... assignment operator could not be generated"
Chris@16 30 # pragma warning( disable: 4512 )
Chris@16 31 // "Function call with parameters that may be unsafe" in
Chris@16 32 // condition_variable.hpp
Chris@16 33 # pragma warning( disable: 4996 )
Chris@16 34 # endif
Chris@16 35
Chris@16 36 # include <boost/thread/mutex.hpp>
Chris@16 37 # include <boost/thread/condition.hpp>
Chris@16 38
Chris@16 39 # ifdef BOOST_MSVC
Chris@16 40 # pragma warning( pop )
Chris@16 41 # endif
Chris@16 42 #endif
Chris@16 43
Chris@16 44 #include <list>
Chris@16 45 #include <memory> // std::allocator
Chris@16 46
Chris@16 47
Chris@16 48 namespace boost
Chris@16 49 {
Chris@16 50 namespace statechart
Chris@16 51 {
Chris@16 52
Chris@16 53
Chris@16 54
Chris@16 55 template< class Allocator = std::allocator< void > >
Chris@16 56 class fifo_worker : noncopyable
Chris@16 57 {
Chris@16 58 public:
Chris@16 59 //////////////////////////////////////////////////////////////////////////
Chris@16 60 #ifdef BOOST_HAS_THREADS
Chris@16 61 fifo_worker( bool waitOnEmptyQueue = false ) :
Chris@16 62 waitOnEmptyQueue_( waitOnEmptyQueue ),
Chris@16 63 #else
Chris@16 64 fifo_worker() :
Chris@16 65 #endif
Chris@16 66 terminated_( false )
Chris@16 67 {
Chris@16 68 }
Chris@16 69
Chris@16 70 typedef function0< void > work_item;
Chris@16 71
Chris@16 72 // We take a non-const reference so that we can move (i.e. swap) the item
Chris@16 73 // into the queue, what avoids copying the (possibly heap-allocated)
Chris@16 74 // implementation object inside work_item.
Chris@16 75 void queue_work_item( work_item & item )
Chris@16 76 {
Chris@16 77 if ( item.empty() )
Chris@16 78 {
Chris@16 79 return;
Chris@16 80 }
Chris@16 81
Chris@16 82 #ifdef BOOST_HAS_THREADS
Chris@16 83 mutex::scoped_lock lock( mutex_ );
Chris@16 84 #endif
Chris@16 85
Chris@16 86 workQueue_.push_back( work_item() );
Chris@16 87 workQueue_.back().swap( item );
Chris@16 88
Chris@16 89 #ifdef BOOST_HAS_THREADS
Chris@16 90 queueNotEmpty_.notify_one();
Chris@16 91 #endif
Chris@16 92 }
Chris@16 93
Chris@16 94 // Convenience overload so that temporary objects can be passed directly
Chris@16 95 // instead of having to create a work_item object first. Under most
Chris@16 96 // circumstances, this will lead to one unnecessary copy of the
Chris@16 97 // function implementation object.
Chris@16 98 void queue_work_item( const work_item & item )
Chris@16 99 {
Chris@16 100 work_item copy = item;
Chris@16 101 queue_work_item( copy );
Chris@16 102 }
Chris@16 103
Chris@16 104 void terminate()
Chris@16 105 {
Chris@16 106 work_item item = boost::bind( &fifo_worker::terminate_impl, this );
Chris@16 107 queue_work_item( item );
Chris@16 108 }
Chris@16 109
Chris@16 110 // Is not mutex-protected! Must only be called from the thread that also
Chris@16 111 // calls operator().
Chris@16 112 bool terminated() const
Chris@16 113 {
Chris@16 114 return terminated_;
Chris@16 115 }
Chris@16 116
Chris@16 117 unsigned long operator()( unsigned long maxItemCount = 0 )
Chris@16 118 {
Chris@16 119 unsigned long itemCount = 0;
Chris@16 120
Chris@16 121 while ( !terminated() &&
Chris@16 122 ( ( maxItemCount == 0 ) || ( itemCount < maxItemCount ) ) )
Chris@16 123 {
Chris@16 124 work_item item = dequeue_item();
Chris@16 125
Chris@16 126 if ( item.empty() )
Chris@16 127 {
Chris@16 128 // item can only be empty when the queue is empty, which only
Chris@16 129 // happens in ST builds or when users pass false to the fifo_worker
Chris@16 130 // constructor
Chris@16 131 return itemCount;
Chris@16 132 }
Chris@16 133
Chris@16 134 item();
Chris@16 135 ++itemCount;
Chris@16 136 }
Chris@16 137
Chris@16 138 return itemCount;
Chris@16 139 }
Chris@16 140
Chris@16 141 private:
Chris@16 142 //////////////////////////////////////////////////////////////////////////
Chris@16 143 work_item dequeue_item()
Chris@16 144 {
Chris@16 145 #ifdef BOOST_HAS_THREADS
Chris@16 146 mutex::scoped_lock lock( mutex_ );
Chris@16 147
Chris@16 148 if ( !waitOnEmptyQueue_ && workQueue_.empty() )
Chris@16 149 {
Chris@16 150 return work_item();
Chris@16 151 }
Chris@16 152
Chris@16 153 while ( workQueue_.empty() )
Chris@16 154 {
Chris@16 155 queueNotEmpty_.wait( lock );
Chris@16 156 }
Chris@16 157 #else
Chris@16 158 // If the queue happens to run empty in a single-threaded system,
Chris@16 159 // waiting for new work items (which means to loop indefinitely!) is
Chris@16 160 // pointless as there is no way that new work items could find their way
Chris@16 161 // into the queue. The only sensible thing is to exit the loop and
Chris@16 162 // return to the caller in this case.
Chris@16 163 // Users can then queue new work items before calling operator() again.
Chris@16 164 if ( workQueue_.empty() )
Chris@16 165 {
Chris@16 166 return work_item();
Chris@16 167 }
Chris@16 168 #endif
Chris@16 169
Chris@16 170 // Optimization: Swap rather than assign to avoid the copy of the
Chris@16 171 // implementation object inside function
Chris@16 172 work_item result;
Chris@16 173 result.swap( workQueue_.front() );
Chris@16 174 workQueue_.pop_front();
Chris@16 175 return result;
Chris@16 176 }
Chris@16 177
Chris@16 178 void terminate_impl()
Chris@16 179 {
Chris@16 180 terminated_ = true;
Chris@16 181 }
Chris@16 182
Chris@16 183
Chris@16 184 typedef std::list<
Chris@16 185 work_item,
Chris@16 186 typename boost::detail::allocator::rebind_to<
Chris@16 187 Allocator, work_item >::type
Chris@16 188 > work_queue_type;
Chris@16 189
Chris@16 190 work_queue_type workQueue_;
Chris@16 191
Chris@16 192 #ifdef BOOST_HAS_THREADS
Chris@16 193 mutex mutex_;
Chris@16 194 condition queueNotEmpty_;
Chris@16 195 const bool waitOnEmptyQueue_;
Chris@16 196 #endif
Chris@16 197
Chris@16 198 bool terminated_;
Chris@16 199 };
Chris@16 200
Chris@16 201
Chris@16 202
Chris@16 203 } // namespace statechart
Chris@16 204 } // namespace boost
Chris@16 205
Chris@16 206
Chris@16 207
Chris@16 208 #endif