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