Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/core/TclThreadList.h @ 5679

Last change on this file since 5679 was 3318, checked in by rgrieder, 15 years ago

Re-reverting TclThreadManager changes.

File size: 10.2 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#ifndef _TclThreadList_H__
30#define _TclThreadList_H__
31
32#include "CorePrereqs.h"
33
34#include <list>
35
36#include <boost/thread/condition_variable.hpp>
37#include <boost/thread/shared_mutex.hpp>
38#include <boost/thread/locks.hpp>
39
40namespace orxonox
41{
42    template <class T>
43    class TclThreadList
44    {
45        public:
46            void push_front(const T& value);
47            void push_back(const T& value);
48            template <class InputIterator> void insert(typename std::list<T>::iterator position, InputIterator begin, InputIterator end);
49
50            void wait_and_pop_front(T* value);
51            void wait_and_pop_back(T* value);
52            bool try_pop_front(T* value);
53            bool try_pop_back(T* value);
54            void clear();
55
56            size_t size() const;
57            bool empty() const;
58            bool is_in(const T& value) const;
59
60            /**
61                @brief Returns a reference to the list. Don't forget to lock the mutex (see @ref getMutex).
62            */
63            inline std::list<T>& getList()
64                { return this->list_; }
65
66            /**
67                @brief Returns a reference to the list. Don't forget to lock the mutex (see @ref getMutex).
68            */
69            inline const std::list<T>& getList() const
70                { return this->list_; }
71
72            /**
73                @brief Returns a reference to the mutex which might be useful if you want to iterate through the list (see @ref begin and @ref end).
74            */
75            inline boost::shared_mutex& getMutex() const
76                { return this->mutex_; }
77
78        private:
79            std::list<T>                  list_;        ///< A standard list for type T
80            mutable boost::shared_mutex   mutex_;       ///< A mutex to grant exclusive access to the list
81            boost::condition_variable_any condition_;   ///< A condition variable to wake threads waiting for the mutex to become ready
82    };
83
84    /**
85        @brief Pushes a new element to the front of the list. A unique_lock is needed.
86    */
87    template <class T>
88    void TclThreadList<T>::push_front(const T& value)
89    {
90        boost::unique_lock<boost::shared_mutex> lock(this->mutex_);
91        this->list_.push_front(value);
92        lock.unlock();                  // unlock the mutex...
93        this->condition_.notify_all();  // ...then call notify_all to wake threads waiting in wait_and_pop_front/back
94    }
95
96    /**
97        @brief Pushes a new element to the back of the list. A unique_lock is needed.
98    */
99    template <class T>
100    void TclThreadList<T>::push_back(const T& value)
101    {
102        boost::unique_lock<boost::shared_mutex> lock(this->mutex_);
103        this->list_.push_back(value);
104        lock.unlock();                  // unlock the mutex...
105        this->condition_.notify_all();  // ...then call notify_all to wake threads waiting in wait_and_pop_front/back
106    }
107
108    /**
109        @brief Inserts new elements into the list. A unique_lock is needed.
110    */
111    template <class T>
112    template <class InputIterator> void TclThreadList<T>::insert(typename std::list<T>::iterator position, InputIterator begin, InputIterator end)
113    {
114        boost::unique_lock<boost::shared_mutex> lock(this->mutex_);
115        this->list_.insert(position, begin, end);
116        lock.unlock();                  // unlock the mutex...
117        this->condition_.notify_all();  // ...then call notify_all to wake threads waiting in wait_and_pop_front/back
118    }
119
120    /**
121        @brief Waits until the list contains at least one element and then pops and returns the front element.
122        @param value The front value will be stored in the variable referenced by this pointer.
123    */
124    template <class T>
125    void TclThreadList<T>::wait_and_pop_front(T* value)
126    {
127        boost::unique_lock<boost::shared_mutex> lock(this->mutex_);
128
129        while (this->list_.empty())       // check if there's an element in the list
130            this->condition_.wait(lock);  // wait until the condition becomes true (a notification comes from push_front, push_back or insert
131
132        *value = this->list_.front();
133        this->list_.pop_front();
134    }
135
136    /**
137        @brief Waits until the list contains at least one element and then pops and returns the back element.
138        @param value The back value will be stored in the variable referenced by this pointer.
139    */
140    template <class T>
141    void TclThreadList<T>::wait_and_pop_back(T* value)
142    {
143        boost::unique_lock<boost::shared_mutex> lock(this->mutex_);
144
145        while (this->list_.empty())       // check if there's an element in the list
146            this->condition_.wait(lock);  // wait until the condition becomes true (a notification comes from push_front, push_back or insert
147
148        *value = this->list_.back();
149        this->list_.pop_back();
150    }
151
152    /**
153        @brief Pops and returns the front element if there's at least one element in the list.
154        @param value The front value will be stored in the variable referenced by this pointer.
155        @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.
156
157        Needs a unique_lock if there's an element to pop. If not, shared_lock is sufficient.
158    */
159    template <class T>
160    bool TclThreadList<T>::try_pop_front(T* value)
161    {
162        boost::upgrade_lock<boost::shared_mutex> lock(this->mutex_); // gain shared lock
163
164        if (this->list_.empty())
165        {
166            // No elements - return immediately
167            return false;
168        }
169        else
170        {
171            // At least one element - write it into the passed variable and pop it from the list
172            boost::upgrade_to_unique_lock<boost::shared_mutex> unique_lock(lock); // upgrade to unique lock to modify the list
173            *value = this->list_.front();
174            this->list_.pop_front();
175        }
176        return true;
177    }
178
179    /**
180        @brief Pops and returns the back element if there's at least one element in the list.
181        @param value The back value will be stored in the variable referenced by this pointer.
182        @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.
183
184        Needs a unique_lock if there's an element to pop. If not, shared_lock is sufficient.
185    */
186    template <class T>
187    bool TclThreadList<T>::try_pop_back(T* value)
188    {
189        boost::upgrade_lock<boost::shared_mutex> lock(this->mutex_); // gain shared lock
190
191        if (this->list_.empty())
192        {
193            // No elements - return immediately
194            return false;
195        }
196        else
197        {
198            // At least one element - write it into the passed variable and pop it from the list
199            boost::upgrade_to_unique_lock<boost::shared_mutex> unique_lock(lock); // upgrade to unique lock to modify the list
200            *value = this->list_.back();
201            this->list_.pop_back();
202        }
203        return true;
204    }
205
206    /**
207        @brief Clears the list. A unique_lock is needed.
208    */
209    template <class T>
210    void TclThreadList<T>::clear()
211    {
212        boost::unique_lock<boost::shared_mutex> lock(this->mutex_);
213        this->list_.clear();
214    }
215
216    /**
217        @brief Returns the size of the list. A shared_lock is needed.
218
219        Warning: Don't change the list based on the result of size(). Use an atomic function instead. Other threads may change the list
220        beween your call to size() and your further actions, so be careful and use this function only if you really want nothing else than
221        just the size of the list.
222    */
223    template <class T>
224    size_t TclThreadList<T>::size() const
225    {
226        boost::shared_lock<boost::shared_mutex> lock(this->mutex_);
227        return this->list_.size();
228    }
229
230    /**
231        @brief Returns true if the list is empty, false otherwise. A shared_lock is needed.
232
233        Warning: Don't change the list based on the result of empty(). Use an atomic function instead. Other threads may change the list
234        beween your call to empty() and your further actions, so be careful and use this function only if you really want nothing else than
235        just if the list is empty or not.
236    */
237    template <class T>
238    bool TclThreadList<T>::empty() const
239    {
240        boost::shared_lock<boost::shared_mutex> lock(this->mutex_);
241        return this->list_.empty();
242    }
243
244    /**
245        @brief Returns true if a given element is in the list, false otherwise. A shared_lock is needed.
246
247        Warning: The result of this function might be wrong just one instruction after the call. Use this function just to get information
248        about a temporary snapshot and don't change the list based on the result of this function.
249    */
250    template <class T>
251    bool TclThreadList<T>::is_in(const T& value) const
252    {
253        boost::shared_lock<boost::shared_mutex> lock(this->mutex_);
254
255        for (typename std::list<T>::const_iterator it = this->list_.begin(); it != this->list_.end(); ++it)
256            if (*it == value)
257                return true;
258
259        return false;
260    }
261}
262
263#endif /* _TclThreadList_H__ */
Note: See TracBrowser for help on using the repository browser.