ChipMaster's trial hacks on C++CMS starting with v1.2.1. Not sure I'll follow on with the v2 since it looks to be breaking and mostly frivolous.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

485 lines
10 KiB

  1. //
  2. // Copyright (C) 2009-2012 Artyom Beilis (Tonkikh)
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See
  5. // accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt)
  7. //
  8. #ifndef BOOSTER_UTIL_THREAD_H
  9. #define BOOSTER_UTIL_THREAD_H
  10. #include <booster/hold_ptr.h>
  11. #include <booster/noncopyable.h>
  12. #include <booster/refcounted.h>
  13. #include <booster/intrusive_ptr.h>
  14. #include <booster/function.h>
  15. #include <booster/config.h>
  16. namespace booster {
  17. extern "C" void *booster_thread_func(void *);
  18. ///
  19. /// \brief the class that allows to start an execution thread
  20. ///
  21. class BOOSTER_API thread : public noncopyable {
  22. public:
  23. ///
  24. /// Run a function \a cb in separate thread
  25. ///
  26. thread(function<void()> const &cb);
  27. ~thread();
  28. ///
  29. /// Join existing thread
  30. ///
  31. void join();
  32. ///
  33. /// Detach from the thread
  34. ///
  35. void detach();
  36. ///
  37. /// Get number of CPUS, returns 0 if the number is unknown
  38. ///
  39. static unsigned hardware_concurrency();
  40. private:
  41. friend void *booster_thread_func(void *);
  42. struct data;
  43. hold_ptr<data> d;
  44. };
  45. class condition_variable;
  46. ///
  47. /// \brief Mutex object
  48. ///
  49. class BOOSTER_API mutex : public noncopyable {
  50. public:
  51. mutex();
  52. ~mutex();
  53. ///
  54. /// Lock the mutex. If the same thread tries to lock the mutex it holds, the behavior is undefined
  55. /// and would likely lead to deadlock
  56. ///
  57. /// \see unique_lock
  58. ///
  59. void lock();
  60. ///
  61. /// Unlock the mutex. If called for unlocked mutex, the behavior is undefined
  62. ///
  63. /// \see unique_lock
  64. ///
  65. void unlock();
  66. friend class condition_variable;
  67. private:
  68. struct data;
  69. hold_ptr<data> d;
  70. };
  71. ///
  72. /// \brief Recursive mutex object.
  73. ///
  74. /// Unlike \ref mutex, when the same thread tries to lock the mutex that is already locked it would
  75. /// succeed and would require to unlock it same times it was locked.
  76. ///
  77. /// Useful for handling objects locks when the order of functions calls is not known in advice. For example
  78. /// \code
  79. /// void foo()
  80. /// {
  81. /// unique_lock<recursive_mutex> guard(this->lock);
  82. /// bar();
  83. /// baz();
  84. /// }
  85. /// void bar()
  86. /// {
  87. /// unique_lock<recursive_mutex> guard(this->lock);
  88. /// ...
  89. /// }
  90. /// \endcode
  91. ///
  92. /// \see unique_lock
  93. /// \see shared_lock
  94. ///
  95. class BOOSTER_API recursive_mutex : public noncopyable {
  96. public:
  97. recursive_mutex();
  98. ~recursive_mutex();
  99. ///
  100. /// Lock the mutex. \see unique_lock
  101. ///
  102. void lock();
  103. ///
  104. /// Unlock the mutex, \see unique_lock
  105. ///
  106. void unlock();
  107. private:
  108. struct data;
  109. hold_ptr<data> d;
  110. };
  111. ///
  112. /// \brief Recursuve Shared mutex or a.k.a. Read-Write Lock that can be recursively locked by \b readers
  113. ///
  114. /// This class provides two options of locking unique - nobody but me can use the object
  115. /// shared anybody with shared lock can use the object.
  116. ///
  117. class BOOSTER_API recursive_shared_mutex : public noncopyable {
  118. public:
  119. recursive_shared_mutex();
  120. ~recursive_shared_mutex();
  121. ///
  122. /// Same as unique_lock()
  123. ///
  124. /// \note this function is not recursive
  125. ///
  126. void lock() { unique_lock(); }
  127. ///
  128. /// Acquire a unique lock on the object. \see booster::unique_lock
  129. ///
  130. /// \note this function is not recursive
  131. ///
  132. void unique_lock();
  133. ///
  134. /// Acquire a shared lock on the object. \see booster::shared_lock
  135. ///
  136. /// \note the shared_lock() member function is recursive, that means that same thread may acquire
  137. /// it multiple times.
  138. ///
  139. void shared_lock();
  140. ///
  141. /// Release the lock
  142. ///
  143. void unlock();
  144. private:
  145. struct data;
  146. hold_ptr<data> d;
  147. };
  148. ///
  149. /// \brief Shared mutex or a.k.a. Read-Write Lock
  150. ///
  151. /// This class provides two options of locking unique - nobody but me can use the object
  152. /// shared anybody with shared lock can use the object.
  153. ///
  154. class BOOSTER_API shared_mutex : public noncopyable {
  155. public:
  156. shared_mutex();
  157. ~shared_mutex();
  158. ///
  159. /// Same as unique_lock()
  160. ///
  161. void lock() { unique_lock(); }
  162. ///
  163. /// Acquire a unique lock on the object. \see booster::unique_lock
  164. ///
  165. void unique_lock();
  166. ///
  167. /// Acquire a shared lock on the object. \see booster::shared_lock
  168. ///
  169. /// Note this function is not recursive
  170. ///
  171. void shared_lock();
  172. ///
  173. /// Release the lock
  174. ///
  175. void unlock();
  176. private:
  177. struct data;
  178. hold_ptr<data> d;
  179. };
  180. template<typename Mutex>
  181. class unique_lock;
  182. ///
  183. /// \brief This is conditional variable object
  184. ///
  185. /// For detailed description of the concept read http://en.wikipedia.org/wiki/Monitor_(synchronization)
  186. ///
  187. class BOOSTER_API condition_variable {
  188. public:
  189. condition_variable();
  190. ~condition_variable();
  191. ///
  192. /// Wait for the condition atomically unlocking the mutex referenced by m.
  193. ///
  194. /// When the condition occurs the lock on the mutex would be acquired again.
  195. ///
  196. /// Note it is unspecified whether suspicious wakes can occur. It is good idea to check
  197. /// whether the condition hold after this function returns.
  198. ///
  199. void wait(unique_lock<mutex> &m);
  200. ///
  201. /// Notify exactly one waiting process on the condition. If no process waits then the notification
  202. /// would be ignored
  203. ///
  204. void notify_one();
  205. ///
  206. /// Notify all waiting process on the condition. If no process waits then the notification
  207. /// would be ignored
  208. ///
  209. void notify_all();
  210. private:
  211. struct data;
  212. hold_ptr<data> d;
  213. };
  214. /// \cond INTERNAL
  215. namespace details {
  216. struct tls_object;
  217. class key : public refcounted {
  218. public:
  219. key(void (*d)(void *)) :
  220. dtor_(d)
  221. {
  222. }
  223. virtual ~key()
  224. {
  225. }
  226. void *get();
  227. void set(void *);
  228. void destroy(void *p)
  229. {
  230. dtor_(p);
  231. }
  232. virtual tls_object *get_object() = 0;
  233. private:
  234. void (*dtor_)(void *);
  235. };
  236. BOOSTER_API intrusive_ptr<key> make_key(void (*dtor)(void *));
  237. struct tls_object {
  238. tls_object(intrusive_ptr<key> p) :
  239. the_key(p),
  240. obj(0)
  241. {
  242. }
  243. ~tls_object()
  244. {
  245. the_key->destroy(obj);
  246. obj = 0;
  247. }
  248. intrusive_ptr<key> the_key;
  249. void *obj;
  250. };
  251. inline void key::set(void *p)
  252. {
  253. get_object()->obj = p;
  254. }
  255. inline void *key::get()
  256. {
  257. return get_object()->obj;
  258. }
  259. } // details
  260. /// \endcond
  261. ///
  262. /// \brief Thread specific pointer
  263. ///
  264. /// Thread specific pointer is NULL for all threads. So on first use it is expected
  265. /// to be initialized.
  266. ///
  267. /// The object would be destroyed when the thread exists. If thread_specific_ptr was destroyed
  268. /// before the thread that uses it exited the object would still exist and would be cleaned up
  269. /// on thread exit.
  270. ///
  271. /// Of course an access to thread_specific_ptr object would lead to undefined behavior and would
  272. /// likely is going to crash your program.
  273. ///
  274. /// \note
  275. ///
  276. /// On Windows platform, when CppCMS and Booster are compiled \b statically (not used as DLL) then
  277. /// TLS cleanup for the threads that where not created with booster::thread would not be executed.
  278. ///
  279. /// So when using thread_specific_ptr on Windows platform make sure that you do one of the following:
  280. ///
  281. /// - Use booster::thread_specific_ptr only from threads created by booster::thread (or main thread)
  282. /// - Link dynamically with booster library (use it as DLL)
  283. ///
  284. template<typename T>
  285. class thread_specific_ptr {
  286. public:
  287. ///
  288. /// Create a new thread specific pointer
  289. ///
  290. thread_specific_ptr() : key_(details::make_key(destructor))
  291. {
  292. }
  293. ///
  294. /// Destroy the thread specific pointer
  295. ///
  296. ~thread_specific_ptr()
  297. {
  298. }
  299. ///
  300. /// Get thread specific value, if not initialized returns NULL
  301. ///
  302. T *get() const
  303. {
  304. return static_cast<T*>(key_->get());
  305. }
  306. ///
  307. /// Dereference pointer, if it is NULL the behavior is undefined
  308. ///
  309. T* operator->() const
  310. {
  311. return get();
  312. }
  313. ///
  314. /// Dereference pointer, if it is NULL the behavior is undefined
  315. ///
  316. T& operator*() const
  317. {
  318. return *get();
  319. }
  320. ///
  321. /// Reset the thread specific pointer and set its value to \a new_val.
  322. ///
  323. /// If previous object was not NULL it would be destroyed
  324. ///
  325. void reset(T *new_val = 0)
  326. {
  327. T *p = get();
  328. if(p)
  329. destructor(p);
  330. key_->set(static_cast<void *>(new_val));
  331. }
  332. ///
  333. /// Release exiting pointer and set thread specific pointer to 0.
  334. ///
  335. /// The caller is responsible to destroy the returned object
  336. ///
  337. T *release()
  338. {
  339. T *p = get();
  340. key_->set(0);
  341. return p;
  342. }
  343. private:
  344. static void destructor(void *ptr)
  345. {
  346. delete static_cast<T*>(ptr);
  347. }
  348. intrusive_ptr<details::key> key_;
  349. };
  350. ///
  351. /// \brief a Unique lock guard.
  352. ///
  353. /// Acquire the unique lock in the constructor and release it in the destructor
  354. ///
  355. template<typename Mutex>
  356. class unique_lock : public noncopyable {
  357. public:
  358. /// Acquire the lock
  359. unique_lock(Mutex &m) : m_(&m)
  360. {
  361. m_->lock();
  362. }
  363. /// Release the lock
  364. ~unique_lock()
  365. {
  366. m_->unlock();
  367. }
  368. /// Get the reference to the mutex object
  369. Mutex *mutex() const
  370. {
  371. return m_;
  372. }
  373. private:
  374. Mutex *m_;
  375. };
  376. ///
  377. /// \brief a Shared lock guard.
  378. ///
  379. /// Acquire the shared lock in the constructor and release it in the destructor
  380. ///
  381. template<typename Mutex>
  382. class shared_lock : public noncopyable {
  383. public:
  384. /// Acquire the lock
  385. shared_lock(Mutex &m) : m_(&m)
  386. {
  387. m_->shared_lock();
  388. }
  389. /// Release the lock
  390. ~shared_lock()
  391. {
  392. m_->unlock();
  393. }
  394. /// Get the reference to the mutex object
  395. Mutex *mutex() const
  396. {
  397. return m_;
  398. }
  399. private:
  400. Mutex *m_;
  401. };
  402. #ifdef BOOSTER_POSIX
  403. ///
  404. /// \brief The mutex that can be used by the processes that had forked
  405. ///
  406. /// \note the lock is automatically released when process dies
  407. ///
  408. class BOOSTER_API fork_shared_mutex : public noncopyable {
  409. public:
  410. ///
  411. /// Create a new mutex - should be done before calling to fork()
  412. ///
  413. fork_shared_mutex();
  414. ~fork_shared_mutex();
  415. ///
  416. /// Try to acquire a unique lock on the mutex
  417. ///
  418. bool try_lock() { return try_unique_lock(); }
  419. ///
  420. /// Try to acquire a unique lock on the mutex
  421. ///
  422. bool try_unique_lock();
  423. ///
  424. /// Try to acquire a shared lock on the mutex
  425. ///
  426. bool try_shared_lock();
  427. ///
  428. /// Acquire a unique lock on the mutex
  429. ///
  430. void lock() { return unique_lock(); }
  431. ///
  432. /// Acquire a unique lock on the mutex
  433. ///
  434. void unique_lock();
  435. ///
  436. /// Acquire a shared lock on the mutex
  437. ///
  438. void shared_lock();
  439. ///
  440. /// Release the mutex
  441. ///
  442. void unlock();
  443. private:
  444. struct data;
  445. hold_ptr<data> d;
  446. };
  447. #endif
  448. }//booster
  449. #endif