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
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 )
36 # include <boost/thread/mutex.hpp>
37 # include <boost/thread/condition.hpp>
40 # pragma warning( pop )
45 #include <memory> // std::allocator
55 template< class Allocator
= std::allocator
< void > >
56 class fifo_worker
: noncopyable
59 //////////////////////////////////////////////////////////////////////////
60 #ifdef BOOST_HAS_THREADS
61 fifo_worker( bool waitOnEmptyQueue
= false ) :
62 waitOnEmptyQueue_( waitOnEmptyQueue
),
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
)
82 #ifdef BOOST_HAS_THREADS
83 mutex::scoped_lock
lock( mutex_
);
86 workQueue_
.push_back( work_item() );
87 workQueue_
.back().swap( item
);
89 #ifdef BOOST_HAS_THREADS
90 queueNotEmpty_
.notify_one();
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
);
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
112 bool terminated() const
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();
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
142 //////////////////////////////////////////////////////////////////////////
143 work_item
dequeue_item()
145 #ifdef BOOST_HAS_THREADS
146 mutex::scoped_lock
lock( mutex_
);
148 if ( !waitOnEmptyQueue_
&& workQueue_
.empty() )
153 while ( workQueue_
.empty() )
155 queueNotEmpty_
.wait( lock
);
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() )
170 // Optimization: Swap rather than assign to avoid the copy of the
171 // implementation object inside function
173 result
.swap( workQueue_
.front() );
174 workQueue_
.pop_front();
178 void terminate_impl()
186 typename
boost::detail::allocator::rebind_to
<
187 Allocator
, work_item
>::type
190 work_queue_type workQueue_
;
192 #ifdef BOOST_HAS_THREADS
194 condition queueNotEmpty_
;
195 const bool waitOnEmptyQueue_
;
203 } // namespace statechart