Cinder

  • Main Page
  • Related Pages
  • Namespaces
  • Classes
  • Files
  • Examples
  • File List
  • File Members

include/cinder/ConcurrentCircularBuffer.h

Go to the documentation of this file.
00001 /*
00002  Copyright (c) 2012, The Cinder Project
00003  All rights reserved.
00004  
00005  This code is designed for use with the Cinder C++ library, http://libcinder.org
00006 
00007  Redistribution and use in source and binary forms, with or without modification, are permitted provided that
00008  the following conditions are met:
00009 
00010     * Redistributions of source code must retain the above copyright notice, this list of conditions and
00011     the following disclaimer.
00012     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
00013     the following disclaimer in the documentation and/or other materials provided with the distribution.
00014 
00015  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
00016  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00017  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
00018  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
00019  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00020  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00021  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00022  POSSIBILITY OF SUCH DAMAGE.
00023 */
00024 
00025 
00026 #pragma once
00027 
00028 #include <boost/circular_buffer.hpp>
00029 #include <boost/noncopyable.hpp>
00030 #include "cinder/Thread.h"
00031 
00032 namespace cinder {
00033 
00034 template<typename T>
00035 class ConcurrentCircularBuffer : public boost::noncopyable {
00036   public:
00037     typedef boost::circular_buffer<T> container_type;
00038     typedef typename container_type::size_type size_type;
00039     typedef typename container_type::value_type value_type;
00040     typedef typename boost::call_traits<value_type>::param_type param_type;
00041 
00042     explicit ConcurrentCircularBuffer( size_type capacity )
00043         : mNumUnread( 0 ), mContainer( capacity ), mCanceled( false )
00044     {}
00045 
00046     void pushFront( param_type item ) {
00047         // param_type represents the "best" way to pass a parameter of type value_type to a method
00048         std::unique_lock<std::mutex> lock( mMutex );
00049         while( ! is_not_full_impl() && ! mCanceled ) {
00050             mNotFullCond.wait( lock );
00051         }
00052         if( mCanceled )
00053             return;
00054         mContainer.push_front( item );
00055         ++mNumUnread;
00056         mNotEmptyCond.notify_one();
00057     }
00058 
00059     void popBack(value_type* pItem) {
00060         std::unique_lock<std::mutex> lock( mMutex );
00061         while( ! is_not_empty_impl() && ! mCanceled ) {
00062             mNotEmptyCond.wait( lock );
00063         }
00064         if( mCanceled )
00065             return;
00066         *pItem = mContainer[--mNumUnread];
00067         mNotFullCond.notify_one();
00068     }
00069 
00071     bool tryPushFront( param_type item ) {
00072         // param_type represents the "best" way to pass a parameter of type value_type to a method
00073         std::unique_lock<std::mutex> lock( mMutex );
00074         if( ! is_not_full_impl() )
00075             return false;
00076         mContainer.push_front( item );
00077         ++mNumUnread;
00078         mNotEmptyCond.notify_one(); 
00079         return true;
00080     }
00081 
00083     bool tryPopBack( value_type* pItem ) {
00084         std::unique_lock<std::mutex> lock( mMutex );
00085         if( ! is_not_empty_impl() )
00086             return false;
00087         *pItem = mContainer[--mNumUnread];
00088         mNotFullCond.notify_one();
00089         return true;
00090     }
00091 
00092     bool isNotEmpty() {
00093         std::unique_lock<std::mutex> lock( mMutex );
00094         return is_not_empty_impl();
00095     }
00096 
00097     bool isNotFull() {
00098         std::unique_lock<std::mutex> lock( mMutex );
00099         return is_not_full_impl();
00100     }
00101     
00102     void cancel() {
00103         std::lock_guard<std::mutex> lock( mMutex );
00104         mCanceled = true;
00105         mNotFullCond.notify_all();
00106         mNotEmptyCond.notify_all();
00107     }
00108     
00110     size_t size() const { return (size_t)mContainer.capacity(); }
00111 
00112   private:
00113     bool is_not_empty_impl() const { return mNumUnread > 0; }
00114     bool is_not_full_impl() const { return mNumUnread < mContainer.capacity(); }
00115 
00116     size_type               mNumUnread;
00117     container_type          mContainer;
00118     std::mutex              mMutex;
00119     std::condition_variable mNotEmptyCond;
00120     std::condition_variable mNotFullCond;
00121     bool                    mCanceled;
00122 };
00123 
00124 } // namespace cinder