source: trunk/yat/utility/Queue.h @ 3223

Last change on this file since 3223 was 3223, checked in by Peter, 9 years ago

add pointer to boost::lockfree

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 4.2 KB
Line 
1#ifndef theplu_yat_utility_queue
2#define theplu_yat_utility_queue
3
4// $Id: Queue.h 3223 2014-05-10 02:29:53Z peter $
5//
6// Copyright (C) 2013, 2014 Peter Johansson
7//
8// This program is free software; you can redistribute it and/or modify
9// it under the terms of the GNU General Public License as published by
10// the Free Software Foundation; either version 3 of the License, or
11// (at your option) any later version.
12//
13// This program is distributed in the hope that it will be useful, but
14// WITHOUT ANY WARRANTY; without even the implied warranty of
15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16// General Public License for more details.
17//
18// You should have received a copy of the GNU General Public License
19// along with this program. If not, see <http://www.gnu.org/licenses/>.
20
21#include <boost/thread.hpp>
22
23#include <deque>
24#include <utility>
25
26namespace theplu {
27namespace yat {
28namespace utility {
29
30  /**
31     \brief Multi-thread safe queue
32
33     This class provides a multi-thread safe queue. The Queue is
34     typically shared by multiple threads such that some threads push
35     elements and some pop elements. The Queue is a "first in first
36     out" container and holds the same functionality as the similar
37     <a href="http://www.sgi.com/tech/stl/queue.html">std::queue</a>. The
38     difference is that Queue is multi-thread safe, in other words,
39     when one thread access the Queue, other threads are locked out
40     from access so that only one thread touches the Queue at a time
41     and its behaviour is well defined. In a single-thread application
42     there is no point in using the class as std::queue should be
43     prefereble.
44
45     \note Copy constructor and assignment are available but they are
46     not thread safe in the current implementation.
47
48     \since New in yat 0.11
49
50     \see Boost Library provides a
51     <a href="http://www.boost.org/doc/libs/1_55_0/doc/html/lockfree.html">
52     lock-free queue</a>
53   */
54  template<typename T>
55  class Queue
56  {
57  public:
58    /// Type of object stored in Queue
59    typedef T value_type;
60
61    /**
62       An unsigned integral type. \see size(void)
63    */
64    typedef typename std::deque<T>::size_type size_type;
65
66    /**
67       \brief Create a Queue with no elements
68    */
69    Queue(void) {}
70
71    /**
72       \brief Copy constructor
73
74       \note is not thread safe
75    */
76    Queue(const Queue& other) : q_(other.q_) {}
77
78    /**
79       \return \c true if container's size is zero
80     */
81    bool empty(void) const
82    {
83      boost::unique_lock<boost::mutex> lock(mutex_);
84      return q_.empty();
85    } // lock is released here
86
87
88    /**
89       \brief access next element is queue
90
91       Access the next element is queue. If container is empty,
92       process is waiting until other process is inserting element
93       into container.
94     */
95    void pop(T& value)
96    {
97      boost::unique_lock<boost::mutex> lock(mutex_);
98      while (q_.empty())
99        condition_.wait(lock);
100      // The obvious choice would be to create a temp copy of front,
101      // pop the queue and then return by-value. This is, however,
102      // dangerous becasue if the copy constructor throws, the queue
103      // has been popped and the element is lost. Instead we choose to
104      // pass via passed reference.
105      value = q_.front();
106      q_.pop_front();
107    } // lock is released here
108
109
110    /**
111       \brief insert an element into container
112     */
113    void push(const T& t)
114    {
115      boost::unique_lock<boost::mutex> lock(mutex_);
116      q_.push_back(t);
117      lock.unlock(); // unlock the mutex
118
119      // Notify others that data is ready after we have unlocked
120      condition_.notify_one();
121    }
122
123
124    /**
125       \return Number of elements stored in container
126     */
127    size_type size(void) const
128    {
129      boost::unique_lock<boost::mutex> lock(mutex_);
130      return q_.size();
131    } // lock is released here
132
133
134    /**
135       If Queue is empty() do nothing and return \c false, else pop
136       the element into \a value and return \c true
137     */
138    bool try_pop(T& value)
139    {
140      boost::unique_lock<boost::mutex> lock(mutex_);
141      if (q_.empty())
142        return false;
143      value = q_.front();
144      q_.pop_front();
145      return true;
146    } // lock is released here
147
148
149    /**
150       \brief assignment operator
151
152       \note is not thread safe
153     */
154    Queue& operator=(const Queue& lhs)
155    {
156      q_ = lhs.q_;
157      return *this;
158    }
159
160  private:
161    std::deque<T> q_;
162    mutable boost::mutex mutex_;
163    boost::condition_variable condition_;
164  };
165
166}}}
167#endif
Note: See TracBrowser for help on using the repository browser.