ucommon
thread.h
Go to the documentation of this file.
1 // Copyright (C) 2006-2010 David Sugar, Tycho Softworks.
2 //
3 // This file is part of GNU uCommon C++.
4 //
5 // GNU uCommon C++ is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU Lesser General Public License as published
7 // by the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // GNU uCommon C++ is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public License
16 // along with GNU uCommon C++. If not, see <http://www.gnu.org/licenses/>.
17 
53 #ifndef _UCOMMON_THREAD_H_
54 #define _UCOMMON_THREAD_H_
55 
56 #ifndef _UCOMMON_CPR_H_
57 #include <ucommon/cpr.h>
58 #endif
59 
60 #ifndef _UCOMMON_ACCESS_H_
61 #include <ucommon/access.h>
62 #endif
63 
64 #ifndef _UCOMMON_TIMERS_H_
65 #include <ucommon/timers.h>
66 #endif
67 
68 #ifndef _UCOMMON_MEMORY_H_
69 #include <ucommon/memory.h>
70 #endif
71 
72 NAMESPACE_UCOMMON
73 
74 class SharedPointer;
75 
86 class __EXPORT Conditional
87 {
88 private:
89  friend class ConditionalAccess;
90 
91 #if defined(_MSCONDITIONAL_)
92  CRITICAL_SECTION mutex;
93  CONDITION_VARIABLE cond;
94 #elif defined(_MSWINDOWS_)
95  enum {SIGNAL = 0, BROADCAST = 1};
96  HANDLE events[2];
97  unsigned waiting;
98  CRITICAL_SECTION mlock;
99  CRITICAL_SECTION mutex;
100 #else
101 #ifndef __PTH__
102  class __LOCAL attribute
103  {
104  public:
105  pthread_condattr_t attr;
106  attribute();
107  };
108 
109  __LOCAL static attribute attr;
110 #endif
111 
112  pthread_cond_t cond;
113  pthread_mutex_t mutex;
114 #endif
115 
116 protected:
117  friend class TimedEvent;
118 
124  bool wait(timeout_t timeout);
125 
131  bool wait(struct timespec *timeout);
132 
133 #ifdef _MSWINDOWS_
134  inline void lock(void)
135  {EnterCriticalSection(&mutex);};
136 
137  inline void unlock(void)
138  {LeaveCriticalSection(&mutex);};
139 
140  void wait(void);
141  void signal(void);
142  void broadcast(void);
143 
144 #else
145 
148  inline void lock(void)
149  {pthread_mutex_lock(&mutex);};
150 
154  inline void unlock(void)
155  {pthread_mutex_unlock(&mutex);};
156 
160  inline void wait(void)
161  {pthread_cond_wait(&cond, &mutex);};
162 
166  inline void signal(void)
167  {pthread_cond_signal(&cond);};
168 
172  inline void broadcast(void)
173  {pthread_cond_broadcast(&cond);};
174 #endif
175 
179  Conditional();
180 
184  ~Conditional();
185 
186 public:
187 #if !defined(_MSWINDOWS_) && !defined(__PTH__)
188 
193  static inline pthread_condattr_t *initializer(void)
194  {return &attr.attr;};
195 #endif
196 
203  static void set(struct timespec *hires, timeout_t timeout);
204 };
205 
213 class __EXPORT ConditionalAccess : private Conditional
214 {
215 protected:
216 #if defined _MSCONDITIONAL_
217  CONDITION_VARIABLE bcast;
218 #elif !defined(_MSWINDOWS_)
219  pthread_cond_t bcast;
220 #endif
221 
222  unsigned pending, waiting, sharing;
223 
229  bool waitSignal(timeout_t timeout);
230 
236  bool waitBroadcast(timeout_t timeout);
237 
238 
244  bool waitSignal(struct timespec *timeout);
245 
251  bool waitBroadcast(struct timespec *timeout);
252 
259  inline static void set(struct timespec *hires, timeout_t timeout)
260  {Conditional::set(hires, timeout);};
261 
262 
263 #ifdef _MSWINDOWS_
264  inline void lock(void)
265  {EnterCriticalSection(&mutex);};
266 
267  inline void unlock(void)
268  {LeaveCriticalSection(&mutex);};
269 
270  void waitSignal(void);
271  void waitBroadcast(void);
272 
273  inline void signal(void)
274  {Conditional::signal();};
275 
276  inline void broadcast(void)
278 
279 #else
280 
283  inline void lock(void)
284  {pthread_mutex_lock(&mutex);};
285 
289  inline void unlock(void)
290  {pthread_mutex_unlock(&mutex);};
291 
295  inline void waitSignal(void)
296  {pthread_cond_wait(&cond, &mutex);};
297 
301  inline void waitBroadcast(void)
302  {pthread_cond_wait(&bcast, &mutex);};
303 
304 
308  inline void signal(void)
309  {pthread_cond_signal(&cond);};
310 
314  inline void broadcast(void)
315  {pthread_cond_broadcast(&bcast);};
316 #endif
317 public:
322 
327 
331  void access(void);
332 
336  void modify(void);
337 
341  void release(void);
342 
346  void commit(void);
347 
354  void limit_sharing(unsigned max);
355 };
356 
365 class __EXPORT TimedEvent : public Timer
366 {
367 private:
368 #ifdef _MSWINDOWS_
369  HANDLE event;
370 #else
371  pthread_cond_t cond;
372  bool signalled;
373 #endif
374  pthread_mutex_t mutex;
375 
376 protected:
381  void lock(void);
382 
387  void release(void);
388 
396  bool sync(void);
397 
398 public:
402  TimedEvent(void);
403 
408  TimedEvent(timeout_t timeout);
409 
414  TimedEvent(time_t timeout);
415 
419  ~TimedEvent();
420 
426  void signal(void);
427 
434  bool wait(timeout_t timeout);
435 
439  void wait(void);
440 
444  void reset(void);
445 };
446 
454 class __EXPORT RecursiveMutex : private Conditional, public ExclusiveAccess
455 {
456 protected:
457  unsigned waiting;
458  unsigned lockers;
459  pthread_t locker;
460 
461  virtual void _lock(void);
462  virtual void _unlock(void);
463 
464 public:
468  RecursiveMutex();
469 
473  void lock(void);
474 
478  bool lock(timeout_t timeout);
479 
483  void release(void);
484 };
485 
498 class __EXPORT ThreadLock : private ConditionalAccess, public ExclusiveAccess, public SharedAccess
499 {
500 protected:
501  unsigned writers;
502  pthread_t writeid;
503 
504  virtual void _lock(void);
505  virtual void _share(void);
506  virtual void _unlock(void);
507 
508 public:
516  class __EXPORT guard_reader
517  {
518  private:
519  const void *object;
520 
521  public:
526  guard_reader();
527 
532  guard_reader(const void *object);
533 
537  ~guard_reader();
538 
544  void set(const void *object);
545 
549  void release(void);
550 
556  inline void operator=(const void *pointer)
557  {set(pointer);};
558  };
559 
567  class __EXPORT guard_writer
568  {
569  private:
570  const void *object;
571 
572  public:
577  guard_writer();
578 
583  guard_writer(const void *object);
584 
588  ~guard_writer();
589 
595  void set(const void *object);
596 
600  void release(void);
601 
607  inline void operator=(const void *pointer)
608  {set(pointer);};
609  };
610 
614  ThreadLock();
615 
621  bool modify(timeout_t timeout = Timer::inf);
622 
628  bool access(timeout_t timeout = Timer::inf);
629 
636  static void indexing(unsigned size);
637 
645  static bool writer(const void *object, timeout_t timeout = Timer::inf);
646 
654  static bool reader(const void *object, timeout_t timeout = Timer::inf);
655 
660  static void release(const void *object);
661 
665  void release(void);
666 };
667 
678 class __EXPORT ReusableAllocator : protected Conditional
679 {
680 protected:
681  ReusableObject *freelist;
682  unsigned waiting;
683 
688 
694  inline ReusableObject *next(ReusableObject *object)
695  {return object->getNext();};
696 
701  void release(ReusableObject *object);
702 };
703 
714 class __EXPORT ConditionalLock : protected ConditionalAccess, public SharedAccess
715 {
716 protected:
717  class Context : public LinkedObject
718  {
719  public:
720  inline Context(LinkedObject **root) : LinkedObject(root) {};
721 
722  pthread_t thread;
723  unsigned count;
724  };
725 
726  LinkedObject *contexts;
727 
728  virtual void _share(void);
729  virtual void _unlock(void);
730 
731  Context *getContext(void);
732 
733 public:
737  ConditionalLock();
738 
742  ~ConditionalLock();
743 
747  void modify(void);
748 
752  void commit(void);
753 
757  void access(void);
758 
762  void release(void);
763 
768  virtual void exclusive(void);
769 
773  virtual void share(void);
774 };
775 
788 class __EXPORT barrier : private Conditional
789 {
790 private:
791  unsigned count;
792  unsigned waits;
793 
794 public:
799  barrier(unsigned count);
800 
804  ~barrier();
805 
811  void set(unsigned count);
812 
816  void inc(void);
817 
821  void dec(void);
822 
827  unsigned operator++(void);
828 
829  unsigned operator--(void);
830 
834  void wait(void);
835 
842  bool wait(timeout_t timeout);
843 };
844 
853 class __EXPORT Semaphore : public SharedAccess, protected Conditional
854 {
855 protected:
856  unsigned count, waits, used;
857 
858  virtual void _share(void);
859  virtual void _unlock(void);
860 
861 public:
865  Semaphore(unsigned count = 0);
866 
871  void wait(void);
872 
880  bool wait(timeout_t timeout);
881 
886  void set(unsigned count);
887 
891  void release(void);
892 
896  inline void operator++(void)
897  {wait();};
898 
902  inline void operator--(void)
903  {release();};
904 };
905 
919 class __EXPORT Mutex : public ExclusiveAccess
920 {
921 protected:
922  pthread_mutex_t mlock;
923 
924  virtual void _lock(void);
925  virtual void _unlock(void);
926 
927 public:
935  class __EXPORT guard
936  {
937  private:
938  const void *object;
939 
940  public:
945  guard();
946 
951  guard(const void *object);
952 
956  ~guard();
957 
963  void set(const void *object);
964 
968  void release(void);
969 
975  inline void operator=(void *pointer)
976  {set(pointer);};
977  };
978 
979 
983  Mutex();
984 
988  ~Mutex();
989 
993  inline void acquire(void)
994  {pthread_mutex_lock(&mlock);};
995 
999  inline void lock(void)
1000  {pthread_mutex_lock(&mlock);};
1001 
1005  inline void unlock(void)
1006  {pthread_mutex_unlock(&mlock);};
1007 
1011  inline void release(void)
1012  {pthread_mutex_unlock(&mlock);};
1013 
1018  inline static void acquire(pthread_mutex_t *lock)
1019  {pthread_mutex_lock(lock);};
1020 
1025  inline static void release(pthread_mutex_t *lock)
1026  {pthread_mutex_unlock(lock);};
1027 
1034  static void indexing(unsigned size);
1035 
1041  static void protect(const void *pointer);
1042 
1047  static void release(const void *pointer);
1048 };
1049 
1058 class __EXPORT auto_protect
1059 {
1060 private:
1061  // cannot copy...
1062  inline auto_protect(const auto_object &pointer) {};
1063 
1064 protected:
1065  const void *object;
1066 
1067  auto_protect();
1068 
1069 public:
1074  auto_protect(const void *object);
1075 
1080  ~auto_protect();
1081 
1085  void release(void);
1086 
1091  inline bool operator!() const
1092  {return object == NULL;};
1093 
1098  inline operator bool() const
1099  {return object != NULL;};
1100 
1107  void operator=(const void *object);
1108 };
1109 
1121 class __EXPORT LockedPointer
1122 {
1123 private:
1124  friend class locked_release;
1125  pthread_mutex_t mutex;
1127 
1128 protected:
1132  LockedPointer();
1133 
1138  void replace(ObjectProtocol *object);
1139 
1144  ObjectProtocol *dup(void);
1145 
1150  inline void operator=(ObjectProtocol *object)
1151  {replace(object);};
1152 };
1153 
1162 class __EXPORT SharedObject
1163 {
1164 protected:
1165  friend class SharedPointer;
1166 
1175  virtual void commit(SharedPointer *pointer);
1176 
1177 public:
1181  virtual ~SharedObject();
1182 };
1183 
1194 class __EXPORT SharedPointer : protected ConditionalAccess
1195 {
1196 private:
1197  friend class shared_release;
1199 
1200 protected:
1204  SharedPointer();
1205 
1209  ~SharedPointer();
1210 
1217  void replace(SharedObject *object);
1218 
1225  SharedObject *share(void);
1226 };
1227 
1238 class __EXPORT Thread
1239 {
1240 protected:
1241 // may be used in future if we need cancelable threads...
1242 #ifdef _MSWINDOWS_
1243  HANDLE cancellor;
1244 #else
1245  void *cancellor;
1246 #endif
1247 
1248  enum {} reserved; // cancel mode?
1249  pthread_t tid;
1250  size_t stack;
1251  int priority;
1252 
1258  Thread(size_t stack = 0);
1259 
1264  void map(void);
1265 
1269  virtual bool is_active(void);
1270 
1271 public:
1278  void setPriority(void);
1279 
1284  static void yield(void);
1285 
1290  static void sleep(timeout_t timeout);
1291 
1298  static Thread *get(void);
1299 
1303  virtual void run(void) = 0;
1304 
1308  virtual ~Thread();
1309 
1318  virtual void exit(void);
1319 
1323  static void init(void);
1324 
1330  static void policy(int polid);
1331 
1336  static void concurrency(int level);
1337 
1344  static bool equal(pthread_t thread1, pthread_t thread2);
1345 
1350  static pthread_t self(void);
1351 
1352  inline operator bool()
1353  {return is_active();}
1354 
1355  inline bool operator!()
1356  {return !is_active();}
1357 
1358  inline bool isRunning(void)
1359  {return is_active();}
1360 };
1361 
1372 class __EXPORT JoinableThread : public Thread
1373 {
1374 protected:
1375 #ifdef _MSWINDOWS_
1376  HANDLE running;
1377 #else
1378  volatile bool running;
1379 #endif
1380  volatile bool joining;
1381 
1386  JoinableThread(size_t size = 0);
1387 
1392  virtual ~JoinableThread();
1393 
1399  void join(void);
1400 
1401  bool is_active(void);
1402 
1403  virtual void run(void) = 0;
1404 
1405 public:
1406 
1415  void start(int priority = 0);
1416 
1421  inline void background(void)
1422  {start(-1);};
1423 };
1424 
1432 class __EXPORT DetachedThread : public Thread
1433 {
1434 protected:
1435  bool active;
1436 
1441  DetachedThread(size_t size = 0);
1442 
1448  ~DetachedThread();
1449 
1458  void exit(void);
1459 
1460  bool is_active(void);
1461 
1462  virtual void run(void) = 0;
1463 
1464 public:
1471  void start(int priority = 0);
1472 };
1473 
1482 class __EXPORT locked_release
1483 {
1484 protected:
1490  locked_release();
1491 
1497  locked_release(const locked_release &object);
1498 
1499 public:
1506 
1511  ~locked_release();
1512 
1516  void release(void);
1517 
1523  locked_release &operator=(LockedPointer &pointer);
1524 };
1525 
1535 class __EXPORT shared_release
1536 {
1537 protected:
1543  shared_release();
1544 
1550  shared_release(const shared_release &object);
1551 
1552 public:
1558 
1564  ~shared_release();
1565 
1569  void release(void);
1570 
1575  SharedObject *get(void);
1576 
1582  shared_release &operator=(SharedPointer &pointer);
1583 };
1584 
1592 template<class T>
1594 {
1595 public:
1600 
1608  inline const T *dup(void)
1609  {return static_cast<const T*>(SharedPointer::share());};
1610 
1617  inline void replace(T *object)
1618  {SharedPointer::replace(object);};
1619 
1624  inline void operator=(T *object)
1625  {replace(object);};
1626 
1631  inline T *operator*()
1632  {return dup();};
1633 };
1634 
1642 template<class T>
1644 {
1645 public:
1650 
1656  inline T* dup(void)
1657  {return static_cast<T *>(LockedPointer::dup());};
1658 
1663  inline void replace(T *object)
1664  {LockedPointer::replace(object);};
1665 
1670  inline void operator=(T *object)
1671  {replace(object);};
1672 
1678  inline T *operator*()
1679  {return dup();};
1680 };
1681 
1687 template<class T>
1689 {
1690 public:
1695 
1701 
1706  inline T& operator*() const
1707  {return *(static_cast<T&>(object));};
1708 
1713  inline T* operator->() const
1714  {return static_cast<T*>(object);};
1715 
1720  inline T* get(void) const
1721  {return static_cast<T*>(object);};
1722 };
1723 
1729 template<class T>
1731 {
1732 public:
1737 
1744 
1748  inline const T& operator*() const
1749  {return *(static_cast<const T&>(ptr->pointer));};
1750 
1755  inline const T* operator->() const
1756  {return static_cast<const T*>(ptr->pointer);};
1757 
1762  inline const T* get(void) const
1763  {return static_cast<const T*>(ptr->pointer);};
1764 };
1765 
1772 template <class T>
1774 {
1775 public:
1779  inline mutex_pointer() : auto_protect() {};
1780 
1785  inline mutex_pointer(T* object) : auto_protect(object) {};
1786 
1791  inline T& operator*() const
1792  {return *(static_cast<T&>(auto_protect::object));};
1793 
1798  inline T* operator->() const
1799  {return static_cast<T*>(auto_protect::object);};
1800 
1805  inline T* get(void) const
1806  {return static_cast<T*>(auto_protect::object);};
1807 };
1808 
1814 inline void start(JoinableThread *thread, int priority = 0)
1815  {thread->start(priority);}
1816 
1822 inline void start(DetachedThread *thread, int priority = 0)
1823  {thread->start(priority);}
1824 
1829 
1834 
1839 
1843 typedef Mutex mutex_t;
1844 
1849 
1854 
1859 
1864 
1869 inline void wait(barrier_t &barrier)
1870  {barrier.wait();}
1871 
1877 inline void wait(semaphore_t &semaphore, timeout_t timeout = Timer::inf)
1878  {semaphore.wait(timeout);}
1879 
1884 inline void release(semaphore_t &semaphore)
1885  {semaphore.release();}
1886 
1891 inline void acquire(mutex_t &mutex)
1892  {mutex.lock();}
1893 
1898 inline void release(mutex_t &mutex)
1899  {mutex.release();}
1900 
1905 inline void modify(accesslock_t &lock)
1906  {lock.modify();}
1907 
1912 inline void access(accesslock_t &lock)
1913  {lock.access();}
1914 
1920  {lock.release();}
1921 
1927 inline void commit(accesslock_t &lock)
1928  {lock.commit();}
1929 
1935  {lock.exclusive();}
1936 
1941 inline void share(condlock_t &lock)
1942  {lock.share();}
1943 
1948 inline void modify(condlock_t &lock)
1949  {lock.modify();}
1950 
1956 inline void commit(condlock_t &lock)
1957  {lock.commit();}
1958 
1963 inline void access(condlock_t &lock)
1964  {lock.access();}
1965 
1970 inline void release(condlock_t &lock)
1971  {lock.release();}
1972 
1978 inline bool exclusive(rwlock_t &lock, timeout_t timeout = Timer::inf)
1979  {return lock.modify(timeout);}
1980 
1986 inline bool share(rwlock_t &lock, timeout_t timeout = Timer::inf)
1987  {return lock.access(timeout);}
1988 
1993 inline void release(rwlock_t &lock)
1994  {lock.release();}
1995 
2000 inline void lock(rexlock_t &lock)
2001  {lock.lock();}
2002 
2007 inline void release(rexlock_t &lock)
2008  {lock.release();}
2009 
2010 inline bool _sync_protect_(const void *obj)
2011 {
2012  Mutex::protect(obj);
2013  return true;
2014 }
2015 
2016 inline bool _sync_release_(const void *obj)
2017 {
2018  Mutex::release(obj);
2019  return false;
2020 }
2021 
2022 inline bool _rw_reader_(const void *obj)
2023 {
2024  ThreadLock::reader(obj);
2025  return true;
2026 }
2027 
2028 inline bool _rw_writer_(const void *obj)
2029 {
2030  ThreadLock::writer(obj);
2031  return true;
2032 }
2033 
2034 inline bool _rw_release_(const void *obj)
2035 {
2036  ThreadLock::release(obj);
2037  return false;
2038 }
2039 
2040 #define ENTER_EXCLUSIVE \
2041  do { static pthread_mutex_t __sync__ = PTHREAD_MUTEX_INITIALIZER; \
2042  pthread_mutex_lock(&__sync__);
2043 
2044 #define LEAVE_EXCLUSIVE \
2045  pthread_mutex_unlock(&__sync__);} while(0);
2046 
2047 #define SYNC(obj) for(bool _sync_flag_ = _sync_protect_(obj); _sync_flag_; _sync_flag_ = _sync_release_(obj))
2048 
2049 #define SHARED(obj) for(bool _sync_flag_ = _rw_reader_(obj); _sync_flag_; _sync_flag_ = _rw_release_(obj))
2050 
2051 #define EXCLUSIVE(obj) for(bool _sync_flag_ = _rw_writer_(obj); _sync_flag_; _sync_flag_ = _rw_release_(obj))
2052 
2053 END_NAMESPACE
2054 
2055 #endif