Fl_Threads.H 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. #ifndef Fl_Threads_H
  2. #define Fl_Threads_H
  3. typedef void *(*tread_func_t) (void *);
  4. #if !defined( _WIN32) || defined(__CYGWIN__)
  5. // pthreads:
  6. #include <pthread.h>
  7. /// \name fltk/Threads.h
  8. //@{
  9. /** Hides whatever the system uses to identify a thread. Used so
  10. the "toy" interface is portable. */
  11. typedef pthread_t Thread;
  12. /** Fork a new thread and make it run \a f(p). Returns negative number
  13. on error, otherwise \a t is set to the new thread. */
  14. inline int create_thread(Thread& t, tread_func_t f, void* p) {
  15. return pthread_create((pthread_t*)&t, 0, f, p);
  16. }
  17. /**
  18. "Mutual-exclusion lock" for simple multithreaded programs. Calling
  19. lock() will wait until nobody else has the lock and then will
  20. return. <i>Calling lock() more than once will "deadlock"!</i>
  21. To avoid this, use RecursiveMutex.
  22. */
  23. class Fl_Mutex {
  24. friend class Fl_SignalMutex;
  25. pthread_mutex_t mutex;
  26. Fl_Mutex(const Fl_Mutex&);
  27. Fl_Mutex& operator=(const Fl_Mutex&);
  28. protected:
  29. Fl_Mutex(const pthread_mutexattr_t* a) {pthread_mutex_init(&mutex, a);}
  30. public:
  31. Fl_Mutex() {pthread_mutex_init(&mutex, 0);}
  32. void lock() {pthread_mutex_lock(&mutex);}
  33. void unlock() {pthread_mutex_unlock(&mutex);}
  34. bool trylock() {return pthread_mutex_trylock(&mutex) == 0;}
  35. ~Fl_Mutex() {pthread_mutex_destroy(&mutex);}
  36. };
  37. /**
  38. A portable "semaphore". A thread that holds this lock() can call
  39. wait(), which will unlock it, then wait for another thread to
  40. call signal(), then lock() it again.
  41. The other thread can call signal() at any time, though usually
  42. it will have called lock() as well, as the lock can be used to
  43. protect the data that is actually being shared between the threads.
  44. If more than one thread is in wait(), then calling signal_one()
  45. will only wake one of them up. This may be more efficient, and
  46. can be done safely if all threads that call wait() also call
  47. signal_one() just before calling unlock().
  48. Warning: wait() can return even if signal() was not called. You
  49. must then check other data (protected by the lock()) to see if
  50. the condition really is fulfilled. In many cases this is the
  51. best implementation, it is also necessary to work around design
  52. errors in Windows, where always returns after 1/2 second to
  53. avoid a deadlock due to the non-atomic nature of Windows calls.
  54. */
  55. class Fl_SignalMutex : public Fl_Mutex {
  56. pthread_cond_t cond;
  57. public:
  58. Fl_SignalMutex() : Fl_Mutex() {pthread_cond_init(&cond, 0);}
  59. void signal() {pthread_cond_broadcast(&cond);}
  60. void signal_one() {pthread_cond_signal(&cond);}
  61. void wait() {pthread_cond_wait(&cond, &mutex);}
  62. };
  63. // Linux supports recursive locks, use them directly, with some cheating:
  64. #if defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP) || defined(PTHREAD_MUTEX_RECURSIVE)
  65. class Fl_RecursiveMutex : public Fl_Mutex {
  66. public:
  67. Fl_RecursiveMutex();
  68. };
  69. #else // standard pthread mutexes need a bit of work to be recursive:
  70. /**
  71. "Mutual exclusion lock" to protect data in multithreaded programs.
  72. This is a "recursive lock". Calling lock() will wait until nobody
  73. else has the lock and then will take it. Calling lock() multiple
  74. times by the same thread is allowed, and unlock() must then be
  75. called the same number of times before another thread can get the
  76. lock.
  77. */
  78. class Fl_RecursiveMutex : public Fl_Mutex {
  79. pthread_t owner;
  80. int counter;
  81. public:
  82. Fl_RecursiveMutex() : Fl_Mutex(), counter(0) {}
  83. void lock() {
  84. if (!counter || owner != pthread_self()) {
  85. Fl_Mutex::lock();
  86. owner = pthread_self();
  87. counter = 1;
  88. } else {
  89. ++counter;
  90. }
  91. }
  92. bool trylock() {
  93. if (!counter || owner != pthread_self()) {
  94. if (!Fl_Mutex::trylock()) return false;
  95. owner = pthread_self();
  96. }
  97. counter++;
  98. return true;
  99. }
  100. void unlock() {if (!--counter) Fl_Mutex::unlock();}
  101. };
  102. #endif
  103. #else // _WIN32:
  104. //# define _WIN32_WINNT 0x0500
  105. # include <windows.h>
  106. # include <process.h>
  107. // undefine some of the more annoying crap:
  108. # undef DELETE
  109. # undef ERROR
  110. # undef IN
  111. # undef OUT
  112. # undef POINT
  113. # undef far
  114. # undef max
  115. # undef min
  116. # undef near
  117. typedef unsigned long Thread;
  118. inline int create_thread(Thread& t, tread_func_t f, void* p) {
  119. return t = (Thread)_beginthread((void( __cdecl * )( void * ))f, 0, p);
  120. }
  121. class Fl_Mutex {
  122. CRITICAL_SECTION cs;
  123. Fl_Mutex(const Fl_Mutex&);
  124. Fl_Mutex& operator=(const Fl_Mutex&);
  125. public:
  126. Fl_Mutex() {InitializeCriticalSection(&cs);}
  127. void lock() {while (!TryEnterCriticalSection(&cs)) SwitchToThread();}
  128. void unlock() {LeaveCriticalSection(&cs);}
  129. bool trylock() {return TryEnterCriticalSection(&cs);}
  130. ~Fl_Mutex() {DeleteCriticalSection(&cs);}
  131. };
  132. // After many experiments we have determined that this very stupid
  133. // implementation has the lowest overhead:
  134. class Fl_SignalMutex : public Fl_Mutex {
  135. public:
  136. Fl_SignalMutex() : Fl_Mutex() {}
  137. void signal() {}
  138. void signal_one() {}
  139. void wait() {
  140. // the following three calls should be atomic, sigh...
  141. unlock();
  142. SwitchToThread();
  143. lock();
  144. }
  145. };
  146. typedef Fl_Mutex Fl_RecursiveMutex;
  147. #endif
  148. /**
  149. C++ convienence object for locking a Fl_Mutex.
  150. Creating a local one of these will lock() the mutex and it means
  151. unlock() will be called no matter how a function exits, because
  152. the destructor ~Fl_Mutex_Guard() does an unlock().
  153. \code
  154. static Fl_Mutex mutex;
  155. function() {
  156. Fl_Mutex:Guard guard(mutex);
  157. do_stuff;
  158. throw_exceptions;
  159. if (test()) return;
  160. etc;
  161. }
  162. \endcode
  163. */
  164. class Fl_Mutex_Guard {
  165. Fl_Mutex& lock;
  166. public:
  167. Fl_Mutex_Guard(Fl_Mutex& m) : lock(m) {lock.lock();}
  168. Fl_Mutex_Guard(Fl_Mutex* m) : lock(*m) {lock.lock();}
  169. ~Fl_Mutex_Guard() {lock.unlock();}
  170. };
  171. //@}
  172. #endif