The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
thread.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2016 by David White <[email protected]>
3  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #ifndef THREAD_HPP_INCLUDED
16 #define THREAD_HPP_INCLUDED
17 
18 #include <list>
19 
20 #include <boost/cstdint.hpp>
21 #include <boost/noncopyable.hpp>
22 #include <boost/scoped_ptr.hpp>
23 #include <boost/smart_ptr.hpp>
24 
25 struct SDL_Thread;
26 
27 #if defined(_MSC_VER) && _MSC_VER <= 1600
28 /*
29  This is needed because msvc up to 2010 fails to correcty forward declare this struct as a return value this case.
30  And will create corrupt binaries without giving a warning / error.
31 */
32 #include <SDL_mutex.h>
33 #else
34 struct SDL_mutex;
35 struct SDL_cond;
36 #endif
37 
38 // Threading primitives wrapper for SDL_Thread.
39 //
40 // This module defines primitives for wrapping C++ around SDL's threading
41 // interface
42 namespace threading
43 {
44 
45 struct manager
46 {
47  ~manager();
48 };
49 
50 // Threading object.
51 //
52 // This class defines threading objects. One such object represents a
53 // thread and admits killing and joining on threads. Intended to be
54 // used for manipulating threads instead of poking around with SDL_Thread
55 // calls.
56 class thread
57  : private boost::noncopyable
58 {
59 public:
60  // Construct a new thread to start executing the function
61  // pointed to by f. The void* data will be passed to f, to
62  // facilitate passing of parameters to f.
63  //
64  // \param f the function at which the thread should start executing
65  // \param data passed to f
66  //
67  // \pre f != nullptr
68  explicit thread(int (*f)(void*), void* data=nullptr);
69 
70  // Destroy the thread object. This is done by waiting on the
71  // thread with the join() operation, thus blocking until the
72  // thread object has finished its operation.
73  ~thread();
74 
75  // Join (wait) on the thread to finish. When the thread finishes,
76  // the function will return. calling wait() on an already killed
77  // thread is a no-op.
78  void join();
79 
80  void detach();
81 
83 private:
84 
85  SDL_Thread* thread_;
86 };
87 
89 // Binary mutexes.
90 //
91 // Implements an interface to binary mutexes. This class only defines the
92 // mutex itself. Locking is handled through the friend class lock,
93 // and monitor interfacing through condition variables is handled through
94 // the friend class condition.
95 class mutex
96  : private boost::noncopyable
97 {
98 public:
99  mutex();
100  ~mutex();
101 
102  friend class lock;
103  friend class condition;
104 
105 private:
106 
107  SDL_mutex* const m_;
108 };
109 
110 // Binary mutex locking.
111 //
112 // Implements a locking object for mutexes. The creation of a lock
113 // object on a mutex will lock the mutex as long as this object is
114 // not deleted.
115 class lock
116  : private boost::noncopyable
117 {
118 public:
119  // Create a lock object on the mutex given as a parameter to
120  // the constructor. The lock will be held for the duration
121  // of the object existence.
122  // If the mutex is already locked, the constructor will
123  // block until the mutex lock can be acquired.
124  //
125  // \param m the mutex on which we should try to lock.
126  explicit lock(mutex& m);
127  // Delete the lock object, thus releasing the lock acquired
128  // on the mutex which the lock object was created with.
129  ~lock();
130 private:
131 
133 };
134 
135 // Condition variable locking.
136 //
137 // Implements condition variables for mutexes. A condition variable
138 // allows you to free up a lock inside a critical section
139 // of the code and regain it later. Condition classes only make
140 // sense to do operations on, if one already acquired a mutex.
142  : private boost::noncopyable
143 {
144 public:
145  condition();
146  ~condition();
147 
148  // Wait on the condition. When the condition is met, you
149  // have a lock on the mutex and can do work in the critical
150  // section. When the condition is not met, wait blocks until
151  // the condition is met and atomically frees up the lock on
152  // the mutex. One will automatically regain the lock when the
153  // thread unblocks.
154  //
155  // If wait returns false we have an error. In this case one cannot
156  // assume that he has a lock on the mutex anymore.
157  //
158  // \param m the mutex you wish to free the lock for
159  // \returns true: the wait was successful, false: an error occurred
160  //
161  // \pre You have already acquired a lock on mutex m
162  //
163  bool wait(const mutex& m);
164 
166 
167  // wait on the condition with a timeout. Basically the same as the
168  // wait() function, but if the lock is not acquired before the
169  // timeout, the function returns with an error.
170  //
171  // \param m the mutex you wish free the lock for.
172  // \param timeout the allowed timeout in milliseconds (ms)
173  // \returns result based on whether condition was met, it timed out,
174  // or there was an error
175  WAIT_TIMEOUT_RESULT wait_timeout(const mutex& m, unsigned int timeout);
176  // signal the condition and wake up one thread waiting on the
177  // condition. If no thread is waiting, notify_one() is a no-op.
178  // Does not unlock the mutex.
179  bool notify_one();
180 
181  // signal all threads waiting on the condition and let them contend
182  // for the lock. This is often used when varying resource amounts are
183  // involved and you do not know how many processes might continue.
184  // The function should be used with care, especially if many threads are
185  // waiting on the condition variable.
186  bool notify_all();
187 
188 private:
189 
190  SDL_cond* const cond_;
191 };
192 
193 //class which defines an interface for waiting on an asynchronous operation
194 class waiter {
195 public:
196  enum ACTION { WAIT, ABORT };
197 
198  virtual ~waiter() {}
199  virtual ACTION process() = 0;
200 };
201 
203 
205 
206 typedef std::list<async_operation_ptr> active_operation_list;
207 
208 //class which defines an asynchronous operation. Objects of this class are accessed from
209 //both the worker thread and the calling thread, and so it has 'strange' allocation semantics.
210 //It is allocated by the caller, and generally deleted by the caller. However, in some cases
211 //the asynchronous operation is aborted, and the caller abandons it. The caller cannot still
212 //delete the operation, since the worker thread might still access it, so in the case when the
213 //operation is aborted, the worker thread will delete it.
214 //
215 //The caller should hold these objects using the async_operation_holder class below, which will
216 //handle the delete semantics
218 {
219 public:
220 
222 
224  thread_(), aborted_(false), finished_(), finishedVar_(false), mutex_()
225  {
226  while (!active_.empty() && active_.front().unique())
227  active_.pop_front();
228  }
229  virtual ~async_operation() {}
230 
231  RESULT execute(async_operation_ptr this_ptr, waiter& wait);
232 
233  mutex& get_mutex() { return mutex_; }
234 
235  virtual void run() = 0;
236 
237  //notify that the operation is finished. Can be called from within the thread
238  //while holding the mutex and after checking is_aborted()
239  //if we want to be sure that if the operation is completed, the caller is notified.
240  //will be called in any case after the operation returns
241  bool notify_finished();
242 
243  //must hold the mutex before calling this function from the worker thread
244  bool is_aborted() const { return aborted_; }
245 
246 private:
247  boost::scoped_ptr<thread> thread_;
248  bool aborted_;
252 
253  static active_operation_list active_;
254 };
255 
256 }
257 
258 #endif
virtual ~waiter()
Definition: thread.hpp:198
boost::shared_ptr< async_operation > async_operation_ptr
Definition: thread.hpp:202
thread(int(*f)(void *), void *data=nullptr)
Definition: thread.cpp:58
SDL_Thread * thread_
Definition: thread.hpp:85
boost::uint32_t uint32_t
Definition: xbrz.hpp:45
boost::scoped_ptr< thread > thread_
Definition: thread.hpp:247
RESULT execute(async_operation_ptr this_ptr, waiter &wait)
Definition: thread.cpp:151
GLint GLenum GLsizei GLint GLsizei const GLvoid * data
Definition: glew.h:1347
WAIT_TIMEOUT_RESULT wait_timeout(const mutex &m, unsigned int timeout)
Definition: thread.cpp:113
static active_operation_list active_
Definition: thread.hpp:253
bool is_aborted() const
Definition: thread.hpp:244
SDL_mutex *const m_
Definition: thread.hpp:107
SDL_cond *const cond_
Definition: thread.hpp:190
virtual ACTION process()=0
GLbitfield GLuint64 timeout
Definition: glew.h:4717
lock(mutex &m)
Definition: thread.cpp:90
mutex & m_
Definition: thread.hpp:132
boost::uint32_t get_current_thread_id()
Definition: thread.cpp:30
const GLdouble * m
Definition: glew.h:6968
boost::uint32_t get_id()
Definition: thread.cpp:28
std::list< async_operation_ptr > active_operation_list
Definition: thread.hpp:206
bool wait(const mutex &m)
Definition: thread.cpp:108
GLclampf f
Definition: glew.h:3024