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< none > >
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 = boost::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