ROSE  0.9.9.168
Synchronization.h
1 // WARNING: Changes to this file must be contributed back to Sawyer or else they will
2 // be clobbered by the next update from Sawyer. The Sawyer repository is at
3 // https://github.com/matzke1/sawyer.
4 
5 
6 
7 
8 #ifndef Sawyer_Synchronization_H
9 #define Sawyer_Synchronization_H
10 
11 #include <Sawyer/Sawyer.h>
12 #include <Sawyer/Map.h>
13 
14 #if SAWYER_MULTI_THREADED
15  // It appears as though a certain version of GNU libc interacts badly with C++03 GCC and LLVM compilers. Some system header
16  // file defines _XOPEN_UNIX as "1" and __UINTPTR_TYPE__ as "unsigned long int" but doesn't provide a definition for
17  // "uintptr_t". This triggers a compilation error in <boost/atomic/atomic.hpp> for boost-1.54 because it assumes that
18  // "uintptr_t" is available based on the preprocessor macros and the included files. These errors occur (at a minimum) on
19  // Debian 8.2 and 8.3 using C++03 mode of gcc-4.8.4, gcc-4.9.2, or llvm-3.5.
20  #include <boost/version.hpp>
21  #if __cplusplus < 201103L && BOOST_VERSION == 105400
22  #include <stdint.h> // must be included before <boost/thread.hpp>
23  #endif
24 
25  #include <boost/thread.hpp>
26  #include <boost/thread/barrier.hpp>
27  #include <boost/thread/condition_variable.hpp>
28  #include <boost/thread/mutex.hpp>
29  #include <boost/thread/locks.hpp>
30  #include <boost/thread/once.hpp>
31  #include <boost/thread/recursive_mutex.hpp>
32 #endif
33 
34 namespace Sawyer {
35 
40 struct MultiThreadedTag {};
41 
47 
48 // Used internally as a mutex in a single-threaded environment. Although it doesn't make sense to be able lock or unlock a
49 // mutex in a single-threaded environment, incrementing a data member for each unlock might be useful and it works in
50 // conjunction with NullLockGuard to prevent compilers from warning about unused variables which, at least in the
51 // multi-threaded environment, are used only for their RAII side effects.
52 class NullMutex {
53  size_t n;
54 public:
55  NullMutex(): n(0) {}
56  void lock() {}
57  void unlock() { ++n; }
58  bool try_lock() { return true; }
59 };
60 
61 // Used internally as a lock guard in a single-threaded environment.
63  NullMutex &mutex_;
64 public:
66  : mutex_(m) {
67  lock();
68  }
69  ~NullLockGuard() {
70  unlock();
71  }
72  void lock() {
73  mutex_.lock();
74  }
75  void unlock() {
76  mutex_.unlock();
77  }
78 };
79 
80 // Used internally as a barrier in a single-threaded environment.
81 class NullBarrier {
82 public:
83  explicit NullBarrier(unsigned count) {
84  if (count > 1)
85  throw std::runtime_error("barrier would deadlock");
86  }
87  bool wait() {
88  return true;
89  }
90 };
91 
93 template<typename Mutex>
94 class LockGuard2 {
95  Mutex &m1_, &m2_;
96 public:
97  LockGuard2(Mutex &m1, Mutex &m2): m1_(m1), m2_(m2) {
98 #if SAWYER_MULTI_THREADED
99  boost::lock(m1, m2);
100 #endif
101  }
102  ~LockGuard2() {
103  m1_.unlock();
104  m2_.unlock();
105  }
106 };
107 
108 template<>
110 public:
112 };
113 
115 template<typename SyncTag>
117 
118 template<>
120 #if SAWYER_MULTI_THREADED
121  enum { SUPPORTED = 1 };
122  typedef boost::mutex Mutex;
123  typedef boost::recursive_mutex RecursiveMutex;
124  typedef boost::lock_guard<boost::mutex> LockGuard;
125  typedef boost::unique_lock<boost::mutex> UniqueLock;
126  typedef boost::lock_guard<boost::recursive_mutex> RecursiveLockGuard;
127  typedef boost::condition_variable_any ConditionVariable;
128  typedef boost::barrier Barrier;
129 #else
130  enum { SUPPORTED = 0 };
131  typedef NullMutex Mutex;
132  typedef NullMutex RecursiveMutex;
133  typedef NullLockGuard LockGuard;
134  typedef NullLockGuard UniqueLock;
135  typedef NullLockGuard RecursiveLockGuard;
136  //typedef ... ConditionVariable; -- does not make sense to use this in a single-threaded program
137  typedef NullBarrier Barrier;
138 #endif
140 };
141 
142 
143 template<>
145  enum { SUPPORTED = 0 };
146  typedef NullMutex Mutex;
147  typedef NullMutex RecursiveMutex;
148  typedef NullLockGuard LockGuard;
149  typedef NullLockGuard UniqueLock;
151  //typedef ... ConditionVariable; -- does not make sense to use this in a single-threaded program
152  typedef NullBarrier Barrier;
154 };
155 
156 // Used internally.
157 SAWYER_EXPORT SAWYER_THREAD_TRAITS::RecursiveMutex& bigMutex();
158 
164 SAWYER_EXPORT size_t fastRandomIndex(size_t n);
165 
187 template<typename T>
189  // The implementation needs to handle the case when this object is created on one thread and used in another thread. The
190  // constructor, running in thread A, creates a thread-local repo which doesn't exist in thread B using this object.
191  //
192  // This is a pointer to avoid lack of thread-local dynamic initialization prior to C++11, and to avoid lack of well defined
193  // order when initializing and destroying global variables in C++.
195  static SAWYER_THREAD_LOCAL Repo *repo_;
196 
197 public:
200  if (!repo_)
201  repo_ = new Repo;
202  repo_->insert(reinterpret_cast<uintptr_t>(this), T());
203  }
204 
206  /*implicit*/ MultiInstanceTls(const T& value) {
207  if (!repo_)
208  repo_ = new Repo;
209  repo_->insert(reinterpret_cast<uintptr_t>(this), value);
210  }
211 
213  MultiInstanceTls& operator=(const T &value) {
214  if (!repo_)
215  repo_ = new Repo;
216  repo_->insert(reinterpret_cast<uintptr_t>(this), value);
217  return *this;
218  }
219 
220  ~MultiInstanceTls() {
221  if (repo_)
222  repo_->erase(reinterpret_cast<uintptr_t>(this));
223  }
224 
228  T& get() {
229  if (!repo_)
230  repo_ = new Repo;
231  return repo_->insertMaybeDefault(reinterpret_cast<uintptr_t>(this));
232  }
233  const T& get() const {
234  if (!repo_)
235  repo_ = new Repo;
236  return repo_->insertMaybeDefault(reinterpret_cast<uintptr_t>(this));
237  }
240  T& operator*() {
241  return get();
242  }
243 
244  const T& operator*() const {
245  return get();
246  }
247 
248  T* operator->() {
249  return &get();
250  }
251 
252  const T* operator->() const {
253  return &get();
254  }
255 
259  operator T() const {
260  if (!repo_)
261  repo_ = new Repo;
262  return repo_->insertMaybeDefault(reinterpret_cast<uintptr_t>(this));
263  }
264 };
265 
266 template<typename T>
267 SAWYER_THREAD_LOCAL Container::Map<uintptr_t, T>* MultiInstanceTls<T>::repo_;
268 
269 } // namespace
270 #endif
MultiInstanceTls()
Default-constructed value.
size_t fastRandomIndex(size_t n)
Thread-safe random number generator.
MultiInstanceTls(const T &value)
Initialize value.
Thread local data per object instance.
Locks multiple mutexes.
Name space for the entire library.
Definition: Access.h:11
Tag indicating that an algorithm or API should assume multiple threads.
MultiInstanceTls & operator=(const T &value)
Assignment operator.
Traits for thread synchronization.
Tag indicating that an algorithm or API can assume only a single thread.
Container associating values with keys.
Definition: Sawyer/Map.h:64