Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 10:00:51

0001 #ifndef BOOST_STATECHART_FIFO_WORKER_HPP_INCLUDED
0002 #define BOOST_STATECHART_FIFO_WORKER_HPP_INCLUDED
0003 //////////////////////////////////////////////////////////////////////////////
0004 // Copyright 2002-2008 Andreas Huber Doenni
0005 // Distributed under the Boost Software License, Version 1.0. (See accompany-
0006 // ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0007 //////////////////////////////////////////////////////////////////////////////
0008 
0009 
0010 
0011 #include <boost/assert.hpp>
0012 #include <boost/noncopyable.hpp>
0013 #include <boost/function/function0.hpp>
0014 #include <boost/bind.hpp>
0015 // BOOST_HAS_THREADS, BOOST_MSVC
0016 #include <boost/config.hpp>
0017 
0018 #include <boost/detail/allocator_utilities.hpp>
0019 
0020 #ifdef BOOST_HAS_THREADS
0021 #  ifdef BOOST_MSVC
0022 #    pragma warning( push )
0023      // "conditional expression is constant" in basic_timed_mutex.hpp
0024 #    pragma warning( disable: 4127 )
0025      // "conversion from 'int' to 'unsigned short'" in microsec_time_clock.hpp
0026 #    pragma warning( disable: 4244 )
0027      // "... needs to have dll-interface to be used by clients of class ..."
0028 #    pragma warning( disable: 4251 )
0029      // "... assignment operator could not be generated"
0030 #    pragma warning( disable: 4512 )
0031      // "Function call with parameters that may be unsafe" in
0032      // condition_variable.hpp
0033 #    pragma warning( disable: 4996 )
0034 #  endif
0035 
0036 #  include <boost/thread/mutex.hpp>
0037 #  include <boost/thread/condition.hpp>
0038 
0039 #  ifdef BOOST_MSVC
0040 #    pragma warning( pop )
0041 #  endif
0042 #endif
0043 
0044 #include <list>
0045 #include <memory>   // std::allocator
0046 
0047 
0048 namespace boost
0049 {
0050 namespace statechart
0051 {
0052 
0053 
0054 
0055 template< class Allocator = std::allocator< none > >
0056 class fifo_worker : noncopyable
0057 {
0058   public:
0059     //////////////////////////////////////////////////////////////////////////
0060     #ifdef BOOST_HAS_THREADS
0061     fifo_worker( bool waitOnEmptyQueue = false ) :
0062       waitOnEmptyQueue_( waitOnEmptyQueue ),
0063     #else
0064     fifo_worker() :
0065     #endif
0066       terminated_( false )
0067     {
0068     }
0069 
0070     typedef function0< void > work_item;
0071 
0072     // We take a non-const reference so that we can move (i.e. swap) the item
0073     // into the queue, what avoids copying the (possibly heap-allocated)
0074     // implementation object inside work_item.
0075     void queue_work_item( work_item & item )
0076     {
0077       if ( item.empty() )
0078       {
0079         return;
0080       }
0081 
0082       #ifdef BOOST_HAS_THREADS
0083       mutex::scoped_lock lock( mutex_ );
0084       #endif
0085 
0086       workQueue_.push_back( work_item() );
0087       workQueue_.back().swap( item );
0088 
0089       #ifdef BOOST_HAS_THREADS
0090       queueNotEmpty_.notify_one();
0091       #endif
0092     }
0093 
0094     // Convenience overload so that temporary objects can be passed directly
0095     // instead of having to create a work_item object first. Under most
0096     // circumstances, this will lead to one unnecessary copy of the
0097     // function implementation object.
0098     void queue_work_item( const work_item & item )
0099     {
0100       work_item copy = item;
0101       queue_work_item( copy );
0102     }
0103 
0104     void terminate()
0105     {
0106       work_item item = boost::bind( &fifo_worker::terminate_impl, this );
0107       queue_work_item( item );
0108     }
0109 
0110     // Is not mutex-protected! Must only be called from the thread that also
0111     // calls operator().
0112     bool terminated() const
0113     {
0114       return terminated_;
0115     }
0116 
0117     unsigned long operator()( unsigned long maxItemCount = 0 )
0118     {
0119       unsigned long itemCount = 0;
0120 
0121       while ( !terminated() &&
0122         ( ( maxItemCount == 0 ) || ( itemCount < maxItemCount ) ) )
0123       {
0124         work_item item = dequeue_item();
0125 
0126         if ( item.empty() )
0127         {
0128           // item can only be empty when the queue is empty, which only
0129           // happens in ST builds or when users pass false to the fifo_worker
0130           // constructor
0131           return itemCount;
0132         }
0133 
0134         item();
0135         ++itemCount;
0136       }
0137 
0138       return itemCount;
0139     }
0140 
0141   private:
0142     //////////////////////////////////////////////////////////////////////////
0143     work_item dequeue_item()
0144     {
0145       #ifdef BOOST_HAS_THREADS
0146       mutex::scoped_lock lock( mutex_ );
0147 
0148       if ( !waitOnEmptyQueue_ && workQueue_.empty() )
0149       {
0150         return work_item();
0151       }
0152 
0153       while ( workQueue_.empty() )
0154       {
0155         queueNotEmpty_.wait( lock );
0156       }
0157       #else
0158       // If the queue happens to run empty in a single-threaded system,
0159       // waiting for new work items (which means to loop indefinitely!) is
0160       // pointless as there is no way that new work items could find their way
0161       // into the queue. The only sensible thing is to exit the loop and
0162       // return to the caller in this case.
0163       // Users can then queue new work items before calling operator() again.
0164       if ( workQueue_.empty() )
0165       {
0166         return work_item();
0167       }
0168       #endif
0169 
0170       // Optimization: Swap rather than assign to avoid the copy of the
0171       // implementation object inside function
0172       work_item result;
0173       result.swap( workQueue_.front() );
0174       workQueue_.pop_front();
0175       return result;
0176     }
0177 
0178     void terminate_impl()
0179     {
0180       terminated_ = true;
0181     }
0182 
0183 
0184     typedef std::list<
0185       work_item,
0186       typename boost::detail::allocator::rebind_to<
0187         Allocator, work_item >::type
0188     > work_queue_type;
0189 
0190     work_queue_type workQueue_;
0191 
0192     #ifdef BOOST_HAS_THREADS
0193     mutex mutex_;
0194     condition queueNotEmpty_;
0195     const bool waitOnEmptyQueue_;
0196     #endif
0197 
0198     bool terminated_;
0199 };
0200 
0201 
0202 
0203 } // namespace statechart
0204 } // namespace boost
0205 
0206 
0207 
0208 #endif