My Project
fifo_worker.hpp
Go to the documentation of this file.
1 #ifndef BOOST_STATECHART_FIFO_WORKER_HPP_INCLUDED
2 #define BOOST_STATECHART_FIFO_WORKER_HPP_INCLUDED
3 // 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)
8 
9 
10 
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>
17 
18 #include <boost/detail/allocator_utilities.hpp>
19 
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
35 
36 # include <boost/thread/mutex.hpp>
37 # include <boost/thread/condition.hpp>
38 
39 # ifdef BOOST_MSVC
40 # pragma warning( pop )
41 # endif
42 #endif
43 
44 #include <list>
45 #include <memory> // std::allocator
46 
47 
48 namespace boost
49 {
50 namespace statechart
51 {
52 
53 
54 
55 template< class Allocator = std::allocator< none > >
56 class fifo_worker : noncopyable
57 {
58  public:
60  #ifdef BOOST_HAS_THREADS
61  fifo_worker( bool waitOnEmptyQueue = false ) :
62  waitOnEmptyQueue_( waitOnEmptyQueue ),
63  #else
65  #endif
66  terminated_( false )
67  {
68  }
69 
70  typedef function0< void > work_item;
71 
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 )
76  {
77  if ( item.empty() )
78  {
79  return;
80  }
81 
82  #ifdef BOOST_HAS_THREADS
83  mutex::scoped_lock lock( mutex_ );
84  #endif
85 
86  workQueue_.push_back( work_item() );
87  workQueue_.back().swap( item );
88 
89  #ifdef BOOST_HAS_THREADS
90  queueNotEmpty_.notify_one();
91  #endif
92  }
93 
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 )
99  {
100  work_item copy = item;
101  queue_work_item( copy );
102  }
103 
104  void terminate()
105  {
106  work_item item = boost::bind( &fifo_worker::terminate_impl, this );
107  queue_work_item( item );
108  }
109 
110  // Is not mutex-protected! Must only be called from the thread that also
111  // calls operator().
112  bool terminated() const
113  {
114  return terminated_;
115  }
116 
117  unsigned long operator()( unsigned long maxItemCount = 0 )
118  {
119  unsigned long itemCount = 0;
120 
121  while ( !terminated() &&
122  ( ( maxItemCount == 0 ) || ( itemCount < maxItemCount ) ) )
123  {
124  work_item item = dequeue_item();
125 
126  if ( item.empty() )
127  {
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;
132  }
133 
134  item();
135  ++itemCount;
136  }
137 
138  return itemCount;
139  }
140 
141  private:
143  work_item dequeue_item()
144  {
145  #ifdef BOOST_HAS_THREADS
146  mutex::scoped_lock lock( mutex_ );
147 
148  if ( !waitOnEmptyQueue_ && workQueue_.empty() )
149  {
150  return work_item();
151  }
152 
153  while ( workQueue_.empty() )
154  {
155  queueNotEmpty_.wait( lock );
156  }
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() )
165  {
166  return work_item();
167  }
168  #endif
169 
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();
175  return result;
176  }
177 
178  void terminate_impl()
179  {
180  terminated_ = true;
181  }
182 
183 
184  typedef std::list<
185  work_item,
186  typename boost::detail::allocator::rebind_to<
187  Allocator, work_item >::type
188  > work_queue_type;
189 
190  work_queue_type workQueue_;
191 
192  #ifdef BOOST_HAS_THREADS
193  mutex mutex_;
194  condition queueNotEmpty_;
195  const bool waitOnEmptyQueue_;
196  #endif
197 
198  bool terminated_;
199 };
200 
201 
202 
203 } // namespace statechart
204 } // namespace boost
205 
206 
207 
208 #endif
boost::statechart::fifo_worker::terminate
void terminate()
Definition: fifo_worker.hpp:104
boost::statechart::fifo_worker
Definition: fifo_worker.hpp:57
boost::statechart::result
detail::safe_reaction_result result
Definition: result.hpp:91
boost
Definition: asynchronous_state_machine.hpp:20
boost::statechart::fifo_worker::terminated
bool terminated() const
Definition: fifo_worker.hpp:112
boost::statechart::fifo_worker::queue_work_item
void queue_work_item(work_item &item)
Definition: fifo_worker.hpp:75
boost::statechart::fifo_worker::operator()
unsigned long operator()(unsigned long maxItemCount=0)
Definition: fifo_worker.hpp:117
boost::statechart::fifo_worker::fifo_worker
fifo_worker()
Definition: fifo_worker.hpp:64
boost::statechart::fifo_worker::queue_work_item
void queue_work_item(const work_item &item)
Definition: fifo_worker.hpp:98
boost::statechart::fifo_worker::work_item
function0< void > work_item
Definition: fifo_worker.hpp:70