fix doc example typo
[boost.git] / boost / statechart / fifo_worker.hpp
blobb522407bf58335ca41d182d916d7aa0f9ba39692
1 #ifndef BOOST_STATECHART_FIFO_WORKER_HPP_INCLUDED
2 #define BOOST_STATECHART_FIFO_WORKER_HPP_INCLUDED
3 //////////////////////////////////////////////////////////////////////////////
4 // Copyright 2002-2008 Andreas Huber Doenni
5 // Distributed under the Boost Software License, Version 1.0. (See accompany-
6 // ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 //////////////////////////////////////////////////////////////////////////////
11 #include <boost/assert.hpp>
12 #include <boost/noncopyable.hpp>
13 #include <boost/function/function0.hpp>
14 #include <boost/bind.hpp>
15 // BOOST_HAS_THREADS, BOOST_MSVC
16 #include <boost/config.hpp>
18 #include <boost/detail/allocator_utilities.hpp>
20 #ifdef BOOST_HAS_THREADS
21 # ifdef BOOST_MSVC
22 # pragma warning( push )
23 // "conditional expression is constant" in basic_timed_mutex.hpp
24 # pragma warning( disable: 4127 )
25 // "conversion from 'int' to 'unsigned short'" in microsec_time_clock.hpp
26 # pragma warning( disable: 4244 )
27 // "... needs to have dll-interface to be used by clients of class ..."
28 # pragma warning( disable: 4251 )
29 // "... assignment operator could not be generated"
30 # pragma warning( disable: 4512 )
31 // "Function call with parameters that may be unsafe" in
32 // condition_variable.hpp
33 # pragma warning( disable: 4996 )
34 # endif
36 # include <boost/thread/mutex.hpp>
37 # include <boost/thread/condition.hpp>
39 # ifdef BOOST_MSVC
40 # pragma warning( pop )
41 # endif
42 #endif
44 #include <list>
45 #include <memory> // std::allocator
48 namespace boost
50 namespace statechart
55 template< class Allocator = std::allocator< void > >
56 class fifo_worker : noncopyable
58 public:
59 //////////////////////////////////////////////////////////////////////////
60 #ifdef BOOST_HAS_THREADS
61 fifo_worker( bool waitOnEmptyQueue = false ) :
62 waitOnEmptyQueue_( waitOnEmptyQueue ),
63 #else
64 fifo_worker() :
65 #endif
66 terminated_( false )
70 typedef function0< void > work_item;
72 // We take a non-const reference so that we can move (i.e. swap) the item
73 // into the queue, what avoids copying the (possibly heap-allocated)
74 // implementation object inside work_item.
75 void queue_work_item( work_item & item )
77 if ( item.empty() )
79 return;
82 #ifdef BOOST_HAS_THREADS
83 mutex::scoped_lock lock( mutex_ );
84 #endif
86 workQueue_.push_back( work_item() );
87 workQueue_.back().swap( item );
89 #ifdef BOOST_HAS_THREADS
90 queueNotEmpty_.notify_one();
91 #endif
94 // Convenience overload so that temporary objects can be passed directly
95 // instead of having to create a work_item object first. Under most
96 // circumstances, this will lead to one unnecessary copy of the
97 // function implementation object.
98 void queue_work_item( const work_item & item )
100 work_item copy = item;
101 queue_work_item( copy );
104 void terminate()
106 work_item item = bind( &fifo_worker::terminate_impl, this );
107 queue_work_item( item );
110 // Is not mutex-protected! Must only be called from the thread that also
111 // calls operator().
112 bool terminated() const
114 return terminated_;
117 unsigned long operator()( unsigned long maxItemCount = 0 )
119 unsigned long itemCount = 0;
121 while ( !terminated() &&
122 ( ( maxItemCount == 0 ) || ( itemCount < maxItemCount ) ) )
124 work_item item = dequeue_item();
126 if ( item.empty() )
128 // item can only be empty when the queue is empty, which only
129 // happens in ST builds or when users pass false to the fifo_worker
130 // constructor
131 return itemCount;
134 item();
135 ++itemCount;
138 return itemCount;
141 private:
142 //////////////////////////////////////////////////////////////////////////
143 work_item dequeue_item()
145 #ifdef BOOST_HAS_THREADS
146 mutex::scoped_lock lock( mutex_ );
148 if ( !waitOnEmptyQueue_ && workQueue_.empty() )
150 return work_item();
153 while ( workQueue_.empty() )
155 queueNotEmpty_.wait( lock );
157 #else
158 // If the queue happens to run empty in a single-threaded system,
159 // waiting for new work items (which means to loop indefinitely!) is
160 // pointless as there is no way that new work items could find their way
161 // into the queue. The only sensible thing is to exit the loop and
162 // return to the caller in this case.
163 // Users can then queue new work items before calling operator() again.
164 if ( workQueue_.empty() )
166 return work_item();
168 #endif
170 // Optimization: Swap rather than assign to avoid the copy of the
171 // implementation object inside function
172 work_item result;
173 result.swap( workQueue_.front() );
174 workQueue_.pop_front();
175 return result;
178 void terminate_impl()
180 terminated_ = true;
184 typedef std::list<
185 work_item,
186 typename boost::detail::allocator::rebind_to<
187 Allocator, work_item >::type
188 > work_queue_type;
190 work_queue_type workQueue_;
192 #ifdef BOOST_HAS_THREADS
193 mutex mutex_;
194 condition queueNotEmpty_;
195 const bool waitOnEmptyQueue_;
196 #endif
198 bool terminated_;
203 } // namespace statechart
204 } // namespace boost
208 #endif