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 85 namespace 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 Mutex(const Mutex &)133 Mutex(const Mutex&) {} 134 /// A mutex cannot be assigned operator =(const Mutex &)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 FastMutex(const FastMutex &)179 FastMutex(const FastMutex&) {} 180 /// A mutex cannot be assigned operator =(const FastMutex &)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 Lock(const Lock & l)202 Lock(const Lock& l) : m(l.m) {} 203 /// A lock cannot be assigned operator =(const Lock &)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 Event(const Event &)240 Event(const Event&) {} 241 /// An event cannot be assigned operator =(const Event &)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 ~Terminator()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 terminator(void) const276 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 ~Runnable(void)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 Thread(const Thread &)345 Thread(const Thread&) {} 346 /// A thread cannot be assigned operator =(const Thread &)347 void operator=(const Thread&) {} 348 }; 349 350 }} 351 352 // STATISTICS: support-any 353