source: trunk/yat/utility/BasicQueue.h @ 3938

Last change on this file since 3938 was 3938, checked in by Peter, 2 years ago

let configure fail if compiler is not a C++11 compiler. YAT_HAVE_RVALUE and friends are no longer defined in 'config.h' and guards araound declarations and implementations are removed. refs #949

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 4.6 KB
Line 
1#ifndef theplu_yat_utility_basic_queue
2#define theplu_yat_utility_basic_queue
3
4// $Id: BasicQueue.h 3938 2020-07-16 13:16:56Z peter $
5//
6// Copyright (C) 2017, 2018 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 yat. If not, see <http://www.gnu.org/licenses/>.
20
21#include "config_public.h"
22
23#include <boost/thread.hpp>
24
25namespace theplu {
26namespace yat {
27namespace utility {
28namespace detail {
29
30  /**
31     \internal Base class for Queue and PriorityQueue
32   */
33  template<class Derived, typename T, class Container>
34  class BasicQueue
35  {
36  public:
37    /// Type of object stored
38    typedef typename Container::value_type value_type;
39
40    /**
41       An unsigned integral type. \see size(void)
42    */
43    typedef typename Container::size_type size_type;
44
45    /**
46       Default constructor
47     */
48    BasicQueue(void) {}
49
50    /**
51       Copy constructor
52     */
53    BasicQueue(const BasicQueue& other)
54    {
55      boost::unique_lock<boost::mutex> lock(other.mutex_);
56      q_ = other.q_;
57    } // lock is released here
58
59    /**
60       Construct queue from underlying Container
61     */
62    explicit BasicQueue(const Container& container) : q_(container) {}
63
64    /**
65       \brief clear queue
66
67       \since new in yat 0.15
68     */
69    void clear(void)
70    {
71      boost::unique_lock<boost::mutex> lock(mutex_);
72      return q_.clear();
73    }
74
75
76    /**
77       \return \c true if container's size is zero
78     */
79    bool empty(void) const
80    {
81      boost::unique_lock<boost::mutex> lock(mutex_);
82      return q_.empty();
83    } // lock is released here
84
85
86    /**
87       \brief access next element in queue
88
89       Access the next element is queue. If container is empty,
90       process is waiting until other process is inserting element
91       into container.
92     */
93    void pop(T& value)
94    {
95      boost::unique_lock<boost::mutex> lock(mutex_);
96      while (q_.empty())
97        condition_.wait(lock);
98      // The obvious choice would be to create a temp copy of front,
99      // pop the queue and then return by-value. This is, however,
100      // dangerous becasue if the copy constructor throws, the queue
101      // has been popped and the element is lost. Instead we choose to
102      // pass via passed reference.
103      static_cast<Derived*>(this)->pop_impl(value, lock);
104    } // lock is released here
105
106
107    /**
108       \brief insert an element into container
109     */
110    void push(const T& t)
111    {
112      boost::unique_lock<boost::mutex> lock(mutex_);
113      static_cast<Derived*>(this)->push_impl(t, lock);
114      lock.unlock(); // unlock the mutex
115
116      // Notify others that data is ready after we have unlocked
117      condition_.notify_one();
118    }
119
120
121    /**
122       \brief insert an element into container
123
124       \note only available if configured and built with cxx11 support
125
126       \since New in yat 0.15
127     */
128    void push(T&& t)
129    {
130      boost::unique_lock<boost::mutex> lock(mutex_);
131      static_cast<Derived*>(this)->push_impl(std::move(t), lock);
132      lock.unlock(); // unlock the mutex
133
134      // Notify others that data is ready after we have unlocked
135      condition_.notify_one();
136    }
137
138
139    /**
140       \return Number of elements stored in container
141     */
142    size_type size(void) const
143    {
144      boost::unique_lock<boost::mutex> lock(mutex_);
145      return q_.size();
146    } // lock is released here
147
148
149    /**
150       If Queue is empty() do nothing and return \c false, else pop
151       the element into \a value and return \c true
152     */
153    bool try_pop(T& value)
154    {
155      boost::unique_lock<boost::mutex> lock(mutex_);
156      if (q_.empty())
157        return false;
158      static_cast<Derived*>(this)->pop_impl(value, lock);
159      return true;
160    } // lock is released here
161
162  protected:
163    /**
164       assign other to this
165     */
166    void assign(const BasicQueue& other)
167    {
168      if (this != &other) {
169        // boost::lock guarantees that the two mutexes are locked in
170        // the same order regardless of passed order and thereby
171        // avoiding deadlock when two threads are calling
172        // lhs.assign(rhs) and rhs.assign(lhs) simultaneously.
173        boost::lock(mutex_, other.mutex_);
174        boost::unique_lock<boost::mutex> lock(mutex_, boost::adopt_lock_t());
175        boost::unique_lock<boost::mutex> other_lock(other.mutex_,
176                                                    boost::adopt_lock_t());
177        q_ = other.q_;
178      }
179    }
180
181    /// data
182    Container q_;
183  private:
184    mutable boost::mutex mutex_;
185    boost::condition_variable condition_;
186  };
187
188}}}}
189#endif
Note: See TracBrowser for help on using the repository browser.