Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/libraries/core/command/TclThreadList.h @ 7401

Last change on this file since 7401 was 7401, checked in by landauf, 14 years ago

merged doc branch back to trunk

  • Property svn:eol-style set to native
File size: 10.1 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU 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, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Fabian 'x3n' Landau
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29/**
30    @file
31    @ingroup Command Tcl
32    @brief Definition of TclThreadList.
33*/
34
35#ifndef _TclThreadList_H__
36#define _TclThreadList_H__
37
38#include "core/CorePrereqs.h"
39
40#include <list>
41
42#include <boost/thread/condition_variable.hpp>
43#include <boost/thread/shared_mutex.hpp>
44#include <boost/thread/locks.hpp>
45
46namespace orxonox
47{
48    /**
49        @brief A thread-safe implementation of a message queue, used by TclThreadManager.
50    */
51    template <class T>
52    class TclThreadList
53    {
54        public:
55            void push_front(const T& value);
56            void push_back(const T& value);
57            template <class InputIterator> void insert(typename std::list<T>::iterator position, InputIterator begin, InputIterator end);
58
59            void wait_and_pop_front(T* value);
60            void wait_and_pop_back(T* value);
61            bool try_pop_front(T* value);
62            bool try_pop_back(T* value);
63            void clear();
64
65            size_t size() const;
66            bool empty() const;
67            bool is_in(const T& value) const;
68
69            /**
70                @brief Returns a reference to the list. Don't forget to lock the mutex (see @ref getMutex).
71            */
72            inline std::list<T>& getList()
73                { return this->list_; }
74
75            /**
76                @brief Returns a reference to the list. Don't forget to lock the mutex (see @ref getMutex).
77            */
78            inline const std::list<T>& getList() const
79                { return this->list_; }
80
81            /**
82                @brief Returns a reference to the mutex which might be useful if you want to iterate through the list (see @ref getList()).
83            */
84            inline boost::shared_mutex& getMutex() const
85                { return this->mutex_; }
86
87        private:
88            std::list<T>                  list_;        ///< A standard list for type T
89            mutable boost::shared_mutex   mutex_;       ///< A mutex to grant exclusive access to the list
90            boost::condition_variable_any condition_;   ///< A condition variable to wake threads waiting for the mutex to become ready
91    };
92
93    /**
94        @brief Pushes a new element to the front of the list. A unique_lock is needed.
95    */
96    template <class T>
97    void TclThreadList<T>::push_front(const T& value)
98    {
99        boost::unique_lock<boost::shared_mutex> lock(this->mutex_);
100        this->list_.push_front(value);
101        lock.unlock();                  // unlock the mutex...
102        this->condition_.notify_all();  // ...then call notify_all to wake threads waiting in wait_and_pop_front/back
103    }
104
105    /**
106        @brief Pushes a new element to the back of the list. A unique_lock is needed.
107    */
108    template <class T>
109    void TclThreadList<T>::push_back(const T& value)
110    {
111        boost::unique_lock<boost::shared_mutex> lock(this->mutex_);
112        this->list_.push_back(value);
113        lock.unlock();                  // unlock the mutex...
114        this->condition_.notify_all();  // ...then call notify_all to wake threads waiting in wait_and_pop_front/back
115    }
116
117    /**
118        @brief Inserts new elements into the list. A unique_lock is needed.
119    */
120    template <class T>
121    template <class InputIterator> void TclThreadList<T>::insert(typename std::list<T>::iterator position, InputIterator begin, InputIterator end)
122    {
123        boost::unique_lock<boost::shared_mutex> lock(this->mutex_);
124        this->list_.insert(position, begin, end);
125        lock.unlock();                  // unlock the mutex...
126        this->condition_.notify_all();  // ...then call notify_all to wake threads waiting in wait_and_pop_front/back
127    }
128
129    /**
130        @brief Waits until the list contains at least one element and then pops and returns the front element.
131        @param value The front value will be stored in the variable referenced by this pointer.
132    */
133    template <class T>
134    void TclThreadList<T>::wait_and_pop_front(T* value)
135    {
136        boost::unique_lock<boost::shared_mutex> lock(this->mutex_);
137
138        while (this->list_.empty())       // check if there's an element in the list
139            this->condition_.wait(lock);  // wait until the condition becomes true (a notification comes from push_front, push_back or insert
140
141        *value = this->list_.front();
142        this->list_.pop_front();
143    }
144
145    /**
146        @brief Waits until the list contains at least one element and then pops and returns the back element.
147        @param value The back value will be stored in the variable referenced by this pointer.
148    */
149    template <class T>
150    void TclThreadList<T>::wait_and_pop_back(T* value)
151    {
152        boost::unique_lock<boost::shared_mutex> lock(this->mutex_);
153
154        while (this->list_.empty())       // check if there's an element in the list
155            this->condition_.wait(lock);  // wait until the condition becomes true (a notification comes from push_front, push_back or insert
156
157        *value = this->list_.back();
158        this->list_.pop_back();
159    }
160
161    /**
162        @brief Pops and returns the front element if there's at least one element in the list.
163        @param value The front value will be stored in the variable referenced by this pointer.
164        @return Returns true if there was at least one element in the list (which got poped). If the list was empty, false is returned immediately.
165
166        Needs a unique_lock if there's an element to pop. If not, shared_lock is sufficient.
167    */
168    template <class T>
169    bool TclThreadList<T>::try_pop_front(T* value)
170    {
171        boost::upgrade_lock<boost::shared_mutex> lock(this->mutex_); // gain shared lock
172
173        if (this->list_.empty())
174        {
175            // No elements - return immediately
176            return false;
177        }
178        else
179        {
180            // At least one element - write it into the passed variable and pop it from the list
181            boost::upgrade_to_unique_lock<boost::shared_mutex> unique_lock(lock); // upgrade to unique lock to modify the list
182            *value = this->list_.front();
183            this->list_.pop_front();
184        }
185        return true;
186    }
187
188    /**
189        @brief Pops and returns the back element if there's at least one element in the list.
190        @param value The back value will be stored in the variable referenced by this pointer.
191        @return Returns true if there was at least one element in the list (which got poped). If the list was empty, false is returned immediately.
192
193        Needs a unique_lock if there's an element to pop. If not, shared_lock is sufficient.
194    */
195    template <class T>
196    bool TclThreadList<T>::try_pop_back(T* value)
197    {
198        boost::upgrade_lock<boost::shared_mutex> lock(this->mutex_); // gain shared lock
199
200        if (this->list_.empty())
201        {
202            // No elements - return immediately
203            return false;
204        }
205        else
206        {
207            // At least one element - write it into the passed variable and pop it from the list
208            boost::upgrade_to_unique_lock<boost::shared_mutex> unique_lock(lock); // upgrade to unique lock to modify the list
209            *value = this->list_.back();
210            this->list_.pop_back();
211        }
212        return true;
213    }
214
215    /**
216        @brief Clears the list. A unique_lock is needed.
217    */
218    template <class T>
219    void TclThreadList<T>::clear()
220    {
221        boost::unique_lock<boost::shared_mutex> lock(this->mutex_);
222        this->list_.clear();
223    }
224
225    /**
226        @brief Returns the size of the list. A shared_lock is needed.
227
228        Warning: Don't change the list based on the result of size(). Use an atomic function instead. Other threads may change the list
229        beween your call to size() and your further actions, so be careful and use this function only if you really want nothing else than
230        just the size of the list.
231    */
232    template <class T>
233    size_t TclThreadList<T>::size() const
234    {
235        boost::shared_lock<boost::shared_mutex> lock(this->mutex_);
236        return this->list_.size();
237    }
238
239    /**
240        @brief Returns true if the list is empty, false otherwise. A shared_lock is needed.
241
242        Warning: Don't change the list based on the result of empty(). Use an atomic function instead. Other threads may change the list
243        beween your call to empty() and your further actions, so be careful and use this function only if you really want nothing else than
244        just if the list is empty or not.
245    */
246    template <class T>
247    bool TclThreadList<T>::empty() const
248    {
249        boost::shared_lock<boost::shared_mutex> lock(this->mutex_);
250        return this->list_.empty();
251    }
252
253    /**
254        @brief Returns true if a given element is in the list, false otherwise. A shared_lock is needed.
255
256        Warning: The result of this function might be wrong just one instruction after the call. Use this function just to get information
257        about a temporary snapshot and don't change the list based on the result of this function.
258    */
259    template <class T>
260    bool TclThreadList<T>::is_in(const T& value) const
261    {
262        boost::shared_lock<boost::shared_mutex> lock(this->mutex_);
263
264        for (typename std::list<T>::const_iterator it = this->list_.begin(); it != this->list_.end(); ++it)
265            if (*it == value)
266                return true;
267
268        return false;
269    }
270}
271
272#endif /* _TclThreadList_H__ */
Note: See TracBrowser for help on using the repository browser.