this repo has no description
1/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
2/*
3 * Main authors:
4 * Christian Schulte <schulte@gecode.org>
5 *
6 * Copyright:
7 * Christian Schulte, 2009
8 *
9 * Bugfixes provided by:
10 * David Rijsman <david.rijsman@quintiq.com>
11 *
12 * This file is part of Gecode, the generic constraint
13 * development environment:
14 * http://www.gecode.org
15 *
16 * Permission is hereby granted, free of charge, to any person obtaining
17 * a copy of this software and associated documentation files (the
18 * "Software"), to deal in the Software without restriction, including
19 * without limitation the rights to use, copy, modify, merge, publish,
20 * distribute, sublicense, and/or sell copies of the Software, and to
21 * permit persons to whom the Software is furnished to do so, subject to
22 * the following conditions:
23 *
24 * The above copyright notice and this permission notice shall be
25 * included in all copies or substantial portions of the Software.
26 *
27 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 *
35 */
36
37#include <cstddef>
38
39#ifdef GECODE_THREADS_WINDOWS
40
41#ifndef NOMINMAX
42# define NOMINMAX
43#endif
44
45#ifndef _WIN32_WINNT
46# define _WIN32_WINNT 0x400
47#endif
48
49#ifndef WIN32_LEAN_AND_MEAN
50# define WIN32_LEAN_AND_MEAN
51#endif
52
53#include <windows.h>
54
55#endif
56
57#ifdef GECODE_THREADS_PTHREADS
58
59#include <pthread.h>
60
61#ifdef GECODE_THREADS_OSX_UNFAIR
62
63#include <os/lock.h>
64#include <libkern/OSAtomic.h>
65
66#endif
67
68#endif
69
70/**
71 * \defgroup FuncSupportThread Simple thread and synchronization support
72 *
73 * This is very simplistic, just enough for parallel search engines. Do
74 * not mistake it for a full-fledged thread package.
75 *
76 * If the platform supports threads, the macro GECODE_HAS_THREADS is
77 * defined. If threads are not supported, all classes are
78 * still available, but are noops with the exception of trying to
79 * create a new thread which will throw an exception.
80 *
81 *
82 * \ingroup FuncSupport
83 */
84
85namespace Gecode { namespace Support {
86
87 /**
88 * \brief A mutex for mutual exclausion among several threads
89 *
90 * It is not specified whether the mutex is recursive or not.
91 * Likewise, there is no guarantee of fairness among the
92 * blocking threads.
93 *
94 * \ingroup FuncSupportThread
95 */
96 class Mutex {
97 private:
98#if defined(GECODE_THREADS_WINDOWS)
99 /// Use a simple but more efficient critical section on Windows
100 CRITICAL_SECTION w_cs;
101#elif defined(GECODE_THREADS_OSX_UNFAIR)
102 /// Use unfair lock on macOS if available, OSSpinLock on older macOS
103 union {
104 os_unfair_lock unfair_lck;
105#pragma clang diagnostic push
106#pragma clang diagnostic ignored "-Wdeprecated-declarations"
107 OSSpinLock spin_lck;
108#pragma clang diagnostic pop
109 } u;
110#elif defined(GECODE_THREADS_PTHREADS)
111 /// The Pthread mutex
112 pthread_mutex_t p_m;
113#else
114#error No suitable mutex implementation found
115#endif
116 public:
117 /// Initialize mutex
118 Mutex(void);
119 /// Acquire the mutex and possibly block
120 void acquire(void);
121 /// Try to acquire the mutex, return true if succesful
122 bool tryacquire(void);
123 /// Release the mutex
124 void release(void);
125 /// Delete mutex
126 ~Mutex(void);
127 /// Allocate memory from heap
128 static void* operator new(size_t s);
129 /// Free memory allocated from heap
130 static void operator delete(void* p);
131 private:
132 /// A mutex cannot be copied
133 Mutex(const Mutex&) {}
134 /// A mutex cannot be assigned
135 void operator=(const Mutex&) {}
136 };
137
138#ifndef GECODE_THREADS_PTHREADS_SPINLOCK
139
140 typedef Mutex FastMutex;
141
142#else
143
144 /**
145 * \brief A fast mutex for mutual exclausion among several threads
146 *
147 * This mutex is implemeneted using spin locks on some platforms
148 * and is not guaranteed to be compatible with events. It should be used
149 * for low-contention locks that are only acquired for short periods of
150 * time.
151 *
152 * It is not specified whether the mutex is recursive or not.
153 * Likewise, there is no guarantee of fairness among the
154 * blocking threads.
155 *
156 * \ingroup FuncSupportThread
157 */
158 class FastMutex {
159 private:
160 /// The Pthread spinlock
161 pthread_spinlock_t p_s;
162 public:
163 /// Initialize mutex
164 FastMutex(void);
165 /// Acquire the mutex and possibly block
166 void acquire(void);
167 /// Try to acquire the mutex, return true if succesful
168 bool tryacquire(void);
169 /// Release the mutex
170 void release(void);
171 /// Delete mutex
172 ~FastMutex(void);
173 /// Allocate memory from heap
174 static void* operator new(size_t s);
175 /// Free memory allocated from heap
176 static void operator delete(void* p);
177 private:
178 /// A mutex cannot be copied
179 FastMutex(const FastMutex&) {}
180 /// A mutex cannot be assigned
181 void operator=(const FastMutex&) {}
182 };
183
184#endif
185
186 /**
187 * \brief A lock as a scoped frontend for a mutex
188 *
189 * \ingroup FuncSupportThread
190 */
191 class Lock {
192 private:
193 /// The mutex used for the lock
194 Mutex& m;
195 public:
196 /// Enter lock
197 Lock(Mutex& m0);
198 /// Leave lock
199 ~Lock(void);
200 private:
201 /// A lock cannot be copied
202 Lock(const Lock& l) : m(l.m) {}
203 /// A lock cannot be assigned
204 void operator=(const Lock&) {}
205 };
206
207 /**
208 * \brief An event for synchronization
209 *
210 * An event can be waited on by a single thread until the event is
211 * signalled.
212 *
213 * \ingroup FuncSupportThread
214 */
215 class Event {
216 private:
217#ifdef GECODE_THREADS_WINDOWS
218 /// The Windows specific handle to an event
219 HANDLE w_h;
220#endif
221#ifdef GECODE_THREADS_PTHREADS
222 /// The Pthread mutex
223 pthread_mutex_t p_m;
224 /// The Pthread condition variable
225 pthread_cond_t p_c;
226 /// Whether the event is signalled
227 bool p_s;
228#endif
229 public:
230 /// Initialize event
231 Event(void);
232 /// Signal the event
233 void signal(void);
234 /// Wait until the event becomes signalled
235 void wait(void);
236 /// Delete event
237 ~Event(void);
238 private:
239 /// An event cannot be copied
240 Event(const Event&) {}
241 /// An event cannot be assigned
242 void operator=(const Event&) {}
243 };
244
245 /**
246 * \brief An interface for objects that can be called after a
247 * thread has terminated (after running the thread's destructor)
248 *
249 * \ingroup FuncSupportThread
250 */
251 class Terminator {
252 public:
253 /// Destructor
254 virtual ~Terminator() {}
255 /// The function that is called when the thread has terminated
256 virtual void terminated(void) = 0;
257 };
258
259 /**
260 * \brief An interface for objects that can be run by a thread
261 *
262 * \ingroup FuncSupportThread
263 */
264 class Runnable {
265 private:
266 /// Whether to delete the object when terminated
267 bool d;
268 public:
269 /// Initialize, \a d defines whether object is deleted when terminated
270 Runnable(bool d=true);
271 /// Set whether to delete upon termination
272 void todelete(bool d);
273 /// Return whether to be deleted upon termination
274 bool todelete(void) const;
275 /// Return terminator object
276 virtual Terminator* terminator(void) const { return nullptr; }
277 /// The function that is executed when the thread starts
278 virtual void run(void) = 0;
279 /// Destructor
280 virtual ~Runnable(void) {}
281 /// Allocate memory from heap
282 static void* operator new(size_t s);
283 /// Free memory allocated from heap
284 static void operator delete(void* p);
285 };
286
287 /**
288 * \brief Simple threads
289 *
290 * Threads cannot be created, only runnable objects can be submitted
291 * for execution by a thread. Threads are pooled to avoid
292 * creation/destruction of threads as much as possible.
293 *
294 * \ingroup FuncSupportThread
295 */
296 class Thread {
297 public:
298 /// A real thread
299 class Run {
300 public:
301 /// Next idle thread
302 Run* n;
303 /// Runnable object to execute
304 Runnable* r;
305 /// Event to wait for next runnable object to execute
306 Event e;
307 /// Mutex for synchronization
308 Mutex m;
309 /// Create a new thread
310 GECODE_SUPPORT_EXPORT Run(Runnable* r);
311 /// Infinite loop for execution
312 GECODE_SUPPORT_EXPORT void exec(void);
313 /// Run a runnable object
314 void run(Runnable* r);
315 /// Allocate memory from heap
316 static void* operator new(size_t s);
317 /// Free memory allocated from heap
318 static void operator delete(void* p);
319 };
320 /// Mutex for synchronization
321 GECODE_SUPPORT_EXPORT static Mutex* m(void);
322 /// Idle runners
323 GECODE_SUPPORT_EXPORT static Run* idle;
324 public:
325 /**
326 * \brief Construct a new thread and run \a r
327 *
328 * After \a r terminates, \a r is deleted. After that, the thread
329 * terminates.
330 *
331 * If the operating system does not support any threads, throws an
332 * exception of type Support::OperatingSystemError.
333 */
334 static void run(Runnable* r);
335 /// Put current thread to sleep for \a ms milliseconds
336 static void sleep(unsigned int ms);
337 /// Return number of processing units (1 if information not available)
338 static unsigned int npu(void);
339 /// acquire mutex \a m globally and possibly lock
340 GECODE_SUPPORT_EXPORT static void acquireGlobalMutex(Mutex* m);
341 /// release globally acquired mutex \a m
342 GECODE_SUPPORT_EXPORT static void releaseGlobalMutex(Mutex* m);
343 private:
344 /// A thread cannot be copied
345 Thread(const Thread&) {}
346 /// A thread cannot be assigned
347 void operator=(const Thread&) {}
348 };
349
350}}
351
352// STATISTICS: support-any