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

Last change on this file since 3061 was 3061, checked in by Peter, 10 years ago

mention that copy and assignment are not thread safe

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 3.8 KB
Line 
1#ifndef theplu_yat_utility_queue
2#define theplu_yat_utility_queue
3
4// $Id: Queue.h 3061 2013-07-02 02:05:46Z peter $
5//
6// Copyright (C) 2013 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
25namespace theplu {
26namespace yat {
27namespace utility {
28
29  /**
30     \brief Multi-thread safe queue
31
32     This class provides a multi-thread safe queue. The Queue is
33     typically shared by multiple threads such that some threads push
34     elements and some pop elements. The Queue is a "first in first
35     out" container and holds the same functionality as the similar
36     <a href="http://www.sgi.com/tech/stl/queue.html">std::queue</a>. The
37     difference is that Queue is multi-thread safe, in other words,
38     when one thread access the Queue, other threads are locked out
39     from access so that only one thread touches the Queue at a time
40     and its behaviour is well defined. In a single-thread application
41     there is no point in using the class as std::queue should be
42     prefereble.
43
44     \note Copy constructor and assignment are available but they are
45     not thread safe in the current implementation.
46
47     \since New in yat 0.11
48   */
49  template<typename T>
50  class Queue
51  {
52  public:
53    /// Type of object stored in Queue
54    typedef T value_type;
55
56    /**
57       An unsigned integral type. \see size(void)
58    */
59    typedef typename std::deque<T>::size_type size_type;
60
61    /**
62       \return \c true if container's size is zero
63     */
64    bool empty(void) const
65    {
66      boost::unique_lock<boost::mutex> lock(mutex_);
67      return q_.empty();
68    } // lock is released here
69
70
71    /**
72       \brief access next element is queue
73
74       Access the next element is queue. If container is empty,
75       process is waiting until other process is inserting element
76       into container.
77     */
78    void pop(T& value)
79    {
80      boost::unique_lock<boost::mutex> lock(mutex_);
81      while (q_.empty())
82        condition_.wait(lock);
83      // The obvious choice would be to create a temp copy of front,
84      // pop the queue and then return by-value. This is, however,
85      // dangerous becasue if the copy constructor throws, the queue
86      // has been popped and the element is lost. Instead we choose to
87      // pass via passed reference.
88      value = q_.front();
89      q_.pop_front();
90    } // lock is released here
91
92
93    /**
94       \brief insert an element into container
95     */
96    void push(const T& t)
97    {
98      boost::unique_lock<boost::mutex> lock(mutex_);
99      q_.push_back(t);
100      lock.unlock(); // unlock the mutex
101
102      // Notify others that data is ready after we have unlocked
103      condition_.notify_one();
104    }
105
106
107    /**
108       \return Number of elements stored in container
109     */
110    size_type size(void) const
111    {
112      boost::unique_lock<boost::mutex> lock(mutex_);
113      return q_.size();
114    } // lock is released here
115
116
117    /**
118       If Queue is empty() do nothing and return \c false, else pop
119       the element into \a value and return \c true
120     */
121    bool try_pop(T& value)
122    {
123      boost::unique_lock<boost::mutex> lock(mutex_);
124      if (q_.empty())
125        return false;
126      value = q_.front();
127      q_.pop_front();
128      return true;
129    } // lock is released here
130
131  private:
132    std::deque<T> q_;
133    mutable boost::mutex mutex_;
134    boost::condition_variable condition_;
135
136    // Using compiler generated (not thread safe) copy and assignment
137    //Queue(const Queue&);
138    //Queue& operator=(const Queue&);
139  };
140
141}}}
142#endif
Note: See TracBrowser for help on using the repository browser.