Mercurial > hg > vamp-build-and-test
diff DEPENDENCIES/generic/include/boost/statechart/fifo_worker.hpp @ 16:2665513ce2d3
Add boost headers
author | Chris Cannam |
---|---|
date | Tue, 05 Aug 2014 11:11:38 +0100 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DEPENDENCIES/generic/include/boost/statechart/fifo_worker.hpp Tue Aug 05 11:11:38 2014 +0100 @@ -0,0 +1,208 @@ +#ifndef BOOST_STATECHART_FIFO_WORKER_HPP_INCLUDED +#define BOOST_STATECHART_FIFO_WORKER_HPP_INCLUDED +////////////////////////////////////////////////////////////////////////////// +// Copyright 2002-2008 Andreas Huber Doenni +// Distributed under the Boost Software License, Version 1.0. (See accompany- +// ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +////////////////////////////////////////////////////////////////////////////// + + + +#include <boost/assert.hpp> +#include <boost/noncopyable.hpp> +#include <boost/function/function0.hpp> +#include <boost/bind.hpp> +// BOOST_HAS_THREADS, BOOST_MSVC +#include <boost/config.hpp> + +#include <boost/detail/allocator_utilities.hpp> + +#ifdef BOOST_HAS_THREADS +# ifdef BOOST_MSVC +# pragma warning( push ) + // "conditional expression is constant" in basic_timed_mutex.hpp +# pragma warning( disable: 4127 ) + // "conversion from 'int' to 'unsigned short'" in microsec_time_clock.hpp +# pragma warning( disable: 4244 ) + // "... needs to have dll-interface to be used by clients of class ..." +# pragma warning( disable: 4251 ) + // "... assignment operator could not be generated" +# pragma warning( disable: 4512 ) + // "Function call with parameters that may be unsafe" in + // condition_variable.hpp +# pragma warning( disable: 4996 ) +# endif + +# include <boost/thread/mutex.hpp> +# include <boost/thread/condition.hpp> + +# ifdef BOOST_MSVC +# pragma warning( pop ) +# endif +#endif + +#include <list> +#include <memory> // std::allocator + + +namespace boost +{ +namespace statechart +{ + + + +template< class Allocator = std::allocator< void > > +class fifo_worker : noncopyable +{ + public: + ////////////////////////////////////////////////////////////////////////// + #ifdef BOOST_HAS_THREADS + fifo_worker( bool waitOnEmptyQueue = false ) : + waitOnEmptyQueue_( waitOnEmptyQueue ), + #else + fifo_worker() : + #endif + terminated_( false ) + { + } + + typedef function0< void > work_item; + + // We take a non-const reference so that we can move (i.e. swap) the item + // into the queue, what avoids copying the (possibly heap-allocated) + // implementation object inside work_item. + void queue_work_item( work_item & item ) + { + if ( item.empty() ) + { + return; + } + + #ifdef BOOST_HAS_THREADS + mutex::scoped_lock lock( mutex_ ); + #endif + + workQueue_.push_back( work_item() ); + workQueue_.back().swap( item ); + + #ifdef BOOST_HAS_THREADS + queueNotEmpty_.notify_one(); + #endif + } + + // Convenience overload so that temporary objects can be passed directly + // instead of having to create a work_item object first. Under most + // circumstances, this will lead to one unnecessary copy of the + // function implementation object. + void queue_work_item( const work_item & item ) + { + work_item copy = item; + queue_work_item( copy ); + } + + void terminate() + { + work_item item = boost::bind( &fifo_worker::terminate_impl, this ); + queue_work_item( item ); + } + + // Is not mutex-protected! Must only be called from the thread that also + // calls operator(). + bool terminated() const + { + return terminated_; + } + + unsigned long operator()( unsigned long maxItemCount = 0 ) + { + unsigned long itemCount = 0; + + while ( !terminated() && + ( ( maxItemCount == 0 ) || ( itemCount < maxItemCount ) ) ) + { + work_item item = dequeue_item(); + + if ( item.empty() ) + { + // item can only be empty when the queue is empty, which only + // happens in ST builds or when users pass false to the fifo_worker + // constructor + return itemCount; + } + + item(); + ++itemCount; + } + + return itemCount; + } + + private: + ////////////////////////////////////////////////////////////////////////// + work_item dequeue_item() + { + #ifdef BOOST_HAS_THREADS + mutex::scoped_lock lock( mutex_ ); + + if ( !waitOnEmptyQueue_ && workQueue_.empty() ) + { + return work_item(); + } + + while ( workQueue_.empty() ) + { + queueNotEmpty_.wait( lock ); + } + #else + // If the queue happens to run empty in a single-threaded system, + // waiting for new work items (which means to loop indefinitely!) is + // pointless as there is no way that new work items could find their way + // into the queue. The only sensible thing is to exit the loop and + // return to the caller in this case. + // Users can then queue new work items before calling operator() again. + if ( workQueue_.empty() ) + { + return work_item(); + } + #endif + + // Optimization: Swap rather than assign to avoid the copy of the + // implementation object inside function + work_item result; + result.swap( workQueue_.front() ); + workQueue_.pop_front(); + return result; + } + + void terminate_impl() + { + terminated_ = true; + } + + + typedef std::list< + work_item, + typename boost::detail::allocator::rebind_to< + Allocator, work_item >::type + > work_queue_type; + + work_queue_type workQueue_; + + #ifdef BOOST_HAS_THREADS + mutex mutex_; + condition queueNotEmpty_; + const bool waitOnEmptyQueue_; + #endif + + bool terminated_; +}; + + + +} // namespace statechart +} // namespace boost + + + +#endif