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