Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

316 lines
7.4KB

  1. // Support for concurrent programing -*- C++ -*-
  2. // Copyright (C) 2003-2020 Free Software Foundation, Inc.
  3. //
  4. // This file is part of the GNU ISO C++ Library. This library is free
  5. // software; you can redistribute it and/or modify it under the
  6. // terms of the GNU General Public License as published by the
  7. // Free Software Foundation; either version 3, or (at your option)
  8. // any later version.
  9. // This library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. // Under Section 7 of GPL version 3, you are granted additional
  14. // permissions described in the GCC Runtime Library Exception, version
  15. // 3.1, as published by the Free Software Foundation.
  16. // You should have received a copy of the GNU General Public License and
  17. // a copy of the GCC Runtime Library Exception along with this program;
  18. // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
  19. // <http://www.gnu.org/licenses/>.
  20. /** @file ext/concurrence.h
  21. * This file is a GNU extension to the Standard C++ Library.
  22. */
  23. #ifndef _CONCURRENCE_H
  24. #define _CONCURRENCE_H 1
  25. #pragma GCC system_header
  26. #include <exception>
  27. #include <bits/gthr.h>
  28. #include <bits/functexcept.h>
  29. #include <bits/cpp_type_traits.h>
  30. #include <ext/type_traits.h>
  31. namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)
  32. {
  33. _GLIBCXX_BEGIN_NAMESPACE_VERSION
  34. // Available locking policies:
  35. // _S_single single-threaded code that doesn't need to be locked.
  36. // _S_mutex multi-threaded code that requires additional support
  37. // from gthr.h or abstraction layers in concurrence.h.
  38. // _S_atomic multi-threaded code using atomic operations.
  39. enum _Lock_policy { _S_single, _S_mutex, _S_atomic };
  40. // Compile time constant that indicates prefered locking policy in
  41. // the current configuration.
  42. static const _Lock_policy __default_lock_policy =
  43. #ifndef __GTHREADS
  44. _S_single;
  45. #elif defined _GLIBCXX_HAVE_ATOMIC_LOCK_POLICY
  46. _S_atomic;
  47. #else
  48. _S_mutex;
  49. #endif
  50. // NB: As this is used in libsupc++, need to only depend on
  51. // exception. No stdexception classes, no use of std::string.
  52. class __concurrence_lock_error : public std::exception
  53. {
  54. public:
  55. virtual char const*
  56. what() const throw()
  57. { return "__gnu_cxx::__concurrence_lock_error"; }
  58. };
  59. class __concurrence_unlock_error : public std::exception
  60. {
  61. public:
  62. virtual char const*
  63. what() const throw()
  64. { return "__gnu_cxx::__concurrence_unlock_error"; }
  65. };
  66. class __concurrence_broadcast_error : public std::exception
  67. {
  68. public:
  69. virtual char const*
  70. what() const throw()
  71. { return "__gnu_cxx::__concurrence_broadcast_error"; }
  72. };
  73. class __concurrence_wait_error : public std::exception
  74. {
  75. public:
  76. virtual char const*
  77. what() const throw()
  78. { return "__gnu_cxx::__concurrence_wait_error"; }
  79. };
  80. // Substitute for concurrence_error object in the case of -fno-exceptions.
  81. inline void
  82. __throw_concurrence_lock_error()
  83. { _GLIBCXX_THROW_OR_ABORT(__concurrence_lock_error()); }
  84. inline void
  85. __throw_concurrence_unlock_error()
  86. { _GLIBCXX_THROW_OR_ABORT(__concurrence_unlock_error()); }
  87. #ifdef __GTHREAD_HAS_COND
  88. inline void
  89. __throw_concurrence_broadcast_error()
  90. { _GLIBCXX_THROW_OR_ABORT(__concurrence_broadcast_error()); }
  91. inline void
  92. __throw_concurrence_wait_error()
  93. { _GLIBCXX_THROW_OR_ABORT(__concurrence_wait_error()); }
  94. #endif
  95. class __mutex
  96. {
  97. private:
  98. #if __GTHREADS && defined __GTHREAD_MUTEX_INIT
  99. __gthread_mutex_t _M_mutex = __GTHREAD_MUTEX_INIT;
  100. #else
  101. __gthread_mutex_t _M_mutex;
  102. #endif
  103. __mutex(const __mutex&);
  104. __mutex& operator=(const __mutex&);
  105. public:
  106. __mutex()
  107. {
  108. #if __GTHREADS && ! defined __GTHREAD_MUTEX_INIT
  109. if (__gthread_active_p())
  110. __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex);
  111. #endif
  112. }
  113. #if __GTHREADS && ! defined __GTHREAD_MUTEX_INIT
  114. ~__mutex()
  115. {
  116. if (__gthread_active_p())
  117. __gthread_mutex_destroy(&_M_mutex);
  118. }
  119. #endif
  120. void lock()
  121. {
  122. #if __GTHREADS
  123. if (__gthread_active_p())
  124. {
  125. if (__gthread_mutex_lock(&_M_mutex) != 0)
  126. __throw_concurrence_lock_error();
  127. }
  128. #endif
  129. }
  130. void unlock()
  131. {
  132. #if __GTHREADS
  133. if (__gthread_active_p())
  134. {
  135. if (__gthread_mutex_unlock(&_M_mutex) != 0)
  136. __throw_concurrence_unlock_error();
  137. }
  138. #endif
  139. }
  140. __gthread_mutex_t* gthread_mutex(void)
  141. { return &_M_mutex; }
  142. };
  143. class __recursive_mutex
  144. {
  145. private:
  146. #if __GTHREADS && defined __GTHREAD_RECURSIVE_MUTEX_INIT
  147. __gthread_recursive_mutex_t _M_mutex = __GTHREAD_RECURSIVE_MUTEX_INIT;
  148. #else
  149. __gthread_recursive_mutex_t _M_mutex;
  150. #endif
  151. __recursive_mutex(const __recursive_mutex&);
  152. __recursive_mutex& operator=(const __recursive_mutex&);
  153. public:
  154. __recursive_mutex()
  155. {
  156. #if __GTHREADS && ! defined __GTHREAD_RECURSIVE_MUTEX_INIT
  157. if (__gthread_active_p())
  158. __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex);
  159. #endif
  160. }
  161. #if __GTHREADS && ! defined __GTHREAD_RECURSIVE_MUTEX_INIT
  162. ~__recursive_mutex()
  163. {
  164. if (__gthread_active_p())
  165. __gthread_recursive_mutex_destroy(&_M_mutex);
  166. }
  167. #endif
  168. void lock()
  169. {
  170. #if __GTHREADS
  171. if (__gthread_active_p())
  172. {
  173. if (__gthread_recursive_mutex_lock(&_M_mutex) != 0)
  174. __throw_concurrence_lock_error();
  175. }
  176. #endif
  177. }
  178. void unlock()
  179. {
  180. #if __GTHREADS
  181. if (__gthread_active_p())
  182. {
  183. if (__gthread_recursive_mutex_unlock(&_M_mutex) != 0)
  184. __throw_concurrence_unlock_error();
  185. }
  186. #endif
  187. }
  188. __gthread_recursive_mutex_t* gthread_recursive_mutex(void)
  189. { return &_M_mutex; }
  190. };
  191. /// Scoped lock idiom.
  192. // Acquire the mutex here with a constructor call, then release with
  193. // the destructor call in accordance with RAII style.
  194. class __scoped_lock
  195. {
  196. public:
  197. typedef __mutex __mutex_type;
  198. private:
  199. __mutex_type& _M_device;
  200. __scoped_lock(const __scoped_lock&);
  201. __scoped_lock& operator=(const __scoped_lock&);
  202. public:
  203. explicit __scoped_lock(__mutex_type& __name) : _M_device(__name)
  204. { _M_device.lock(); }
  205. ~__scoped_lock() throw()
  206. { _M_device.unlock(); }
  207. };
  208. #ifdef __GTHREAD_HAS_COND
  209. class __cond
  210. {
  211. private:
  212. #if __GTHREADS && defined __GTHREAD_COND_INIT
  213. __gthread_cond_t _M_cond = __GTHREAD_COND_INIT;
  214. #else
  215. __gthread_cond_t _M_cond;
  216. #endif
  217. __cond(const __cond&);
  218. __cond& operator=(const __cond&);
  219. public:
  220. __cond()
  221. {
  222. #if __GTHREADS && ! defined __GTHREAD_COND_INIT
  223. if (__gthread_active_p())
  224. __GTHREAD_COND_INIT_FUNCTION(&_M_cond);
  225. #endif
  226. }
  227. #if __GTHREADS && ! defined __GTHREAD_COND_INIT
  228. ~__cond()
  229. {
  230. if (__gthread_active_p())
  231. __gthread_cond_destroy(&_M_cond);
  232. }
  233. #endif
  234. void broadcast()
  235. {
  236. #if __GTHREADS
  237. if (__gthread_active_p())
  238. {
  239. if (__gthread_cond_broadcast(&_M_cond) != 0)
  240. __throw_concurrence_broadcast_error();
  241. }
  242. #endif
  243. }
  244. void wait(__mutex *mutex)
  245. {
  246. #if __GTHREADS
  247. {
  248. if (__gthread_cond_wait(&_M_cond, mutex->gthread_mutex()) != 0)
  249. __throw_concurrence_wait_error();
  250. }
  251. #endif
  252. }
  253. void wait_recursive(__recursive_mutex *mutex)
  254. {
  255. #if __GTHREADS
  256. {
  257. if (__gthread_cond_wait_recursive(&_M_cond,
  258. mutex->gthread_recursive_mutex())
  259. != 0)
  260. __throw_concurrence_wait_error();
  261. }
  262. #endif
  263. }
  264. };
  265. #endif
  266. _GLIBCXX_END_NAMESPACE_VERSION
  267. } // namespace
  268. #endif