uvw  2.0.0
thread.hpp
1 #pragma once
2 
3 
4 #include <memory>
5 #include <string>
6 #include <cstddef>
7 #include <type_traits>
8 #include <utility>
9 #include <uv.h>
10 #include "loop.hpp"
11 #include "underlying_type.hpp"
12 
13 
14 namespace uvw {
15 
16 
17 namespace details {
18 
19 
20 enum class UVThreadCreateFlags: std::underlying_type_t<uv_thread_create_flags> {
21  THREAD_NO_FLAGS = UV_THREAD_NO_FLAGS,
22  THREAD_HAS_STACK_SIZE = UV_THREAD_HAS_STACK_SIZE
23 };
24 
25 
26 }
27 
28 
29 class Thread;
30 class ThreadLocalStorage;
31 class Once;
32 class Mutex;
33 class RWLock;
34 class Semaphore;
35 class Condition;
36 class Barrier;
37 
38 
48 class Thread final: public UnderlyingType<Thread, uv_thread_t> {
49  using InternalTask = std::function<void(std::shared_ptr<void>)>;
50 
51  static void createCallback(void *arg) {
52  Thread &thread = *(static_cast<Thread*>(arg));
53  thread.task(thread.data);
54  }
55 
56 public:
57  using Options = details::UVThreadCreateFlags;
58  using Task = InternalTask;
59  using Type = uv_thread_t;
60 
61  explicit Thread(ConstructorAccess ca, std::shared_ptr<Loop> ref, Task t, std::shared_ptr<void> d = nullptr) noexcept
62  : UnderlyingType{ca, std::move(ref)}, data{std::move(d)}, task{std::move(t)}
63  {}
64 
69  static Type self() noexcept {
70  return uv_thread_self();
71  }
72 
79  static bool equal(const Thread &tl, const Thread &tr) noexcept {
80  return !(0 == uv_thread_equal(tl.get(), tr.get()));
81  }
82 
83  ~Thread() noexcept {
84  join();
85  }
86 
91  bool run() noexcept {
92  return (0 == uv_thread_create(get(), &createCallback, this));
93  }
94 
108  bool run(Flags<Options> opts, std::size_t stack = {}) noexcept {
109  uv_thread_options_t params{opts, stack};
110  return (0 == uv_thread_create_ex(get(), &params, &createCallback, this));
111  }
112 
117  bool join() noexcept {
118  return (0 == uv_thread_join(get()));
119  }
120 
121 private:
122  std::shared_ptr<void> data;
123  Task task;
124 };
125 
126 
134 class ThreadLocalStorage final: public UnderlyingType<ThreadLocalStorage, uv_key_t> {
135 public:
136  explicit ThreadLocalStorage(ConstructorAccess ca, std::shared_ptr<Loop> ref) noexcept
137  : UnderlyingType{ca, std::move(ref)}
138  {
139  uv_key_create(UnderlyingType::get());
140  }
141 
142  ~ThreadLocalStorage() noexcept {
143  uv_key_delete(UnderlyingType::get());
144  }
145 
151  template<typename T>
152  T* get() noexcept {
153  return static_cast<T*>(uv_key_get(UnderlyingType::get()));
154  }
155 
161  template<typename T>
162  void set(T *value) noexcept {
163  return uv_key_set(UnderlyingType::get(), value);
164  }
165 };
166 
167 
174 class Once final: public UnderlyingType<Once, uv_once_t> {
175  static uv_once_t* guard() noexcept {
176  static uv_once_t once = UV_ONCE_INIT;
177  return &once;
178  }
179 
180 public:
181  using UnderlyingType::UnderlyingType;
182 
192  template<typename F>
193  static void once(F &&f) noexcept {
194  using CallbackType = void(*)(void);
195  static_assert(std::is_convertible_v<F, CallbackType>);
196  CallbackType cb = f;
197  uv_once(guard(), cb);
198  }
199 };
200 
201 
210 class Mutex final: public UnderlyingType<Mutex, uv_mutex_t> {
211  friend class Condition;
212 
213 public:
214  explicit Mutex(ConstructorAccess ca, std::shared_ptr<Loop> ref, bool recursive = false) noexcept
215  : UnderlyingType{ca, std::move(ref)}
216  {
217  if(recursive) {
218  uv_mutex_init_recursive(get());
219  } else {
220  uv_mutex_init(get());
221  }
222  }
223 
224  ~Mutex() noexcept {
225  uv_mutex_destroy(get());
226  }
227 
231  void lock() noexcept {
232  uv_mutex_lock(get());
233  }
234 
239  bool tryLock() noexcept {
240  return (0 == uv_mutex_trylock(get()));
241  }
242 
246  void unlock() noexcept {
247  uv_mutex_unlock(get());
248  }
249 };
250 
251 
255 class RWLock final: public UnderlyingType<RWLock, uv_rwlock_t> {
256 public:
257  explicit RWLock(ConstructorAccess ca, std::shared_ptr<Loop> ref) noexcept
258  : UnderlyingType{ca, std::move(ref)}
259  {
260  uv_rwlock_init(get());
261  }
262 
263  ~RWLock() noexcept {
264  uv_rwlock_destroy(get());
265  }
266 
270  void rdLock() noexcept {
271  uv_rwlock_rdlock(get());
272  }
273 
278  bool tryRdLock() noexcept {
279  return (0 == uv_rwlock_tryrdlock(get()));
280  }
281 
285  void rdUnlock() noexcept {
286  uv_rwlock_rdunlock(get());
287  }
288 
292  void wrLock() noexcept {
293  uv_rwlock_wrlock(get());
294  }
295 
300  bool tryWrLock() noexcept {
301  return (0 == uv_rwlock_trywrlock(get()));
302  }
303 
307  void wrUnlock() noexcept {
308  uv_rwlock_wrunlock(get());
309  }
310 };
311 
312 
320 class Semaphore final: public UnderlyingType<Semaphore, uv_sem_t> {
321 public:
322  explicit Semaphore(ConstructorAccess ca, std::shared_ptr<Loop> ref, unsigned int value) noexcept
323  : UnderlyingType{ca, std::move(ref)}
324  {
325  uv_sem_init(get(), value);
326  }
327 
328  ~Semaphore() noexcept {
329  uv_sem_destroy(get());
330  }
331 
335  void post() noexcept {
336  uv_sem_post(get());
337  }
338 
342  void wait() noexcept {
343  uv_sem_wait(get());
344  }
345 
350  bool tryWait() noexcept {
351  return (0 == uv_sem_trywait(get()));
352  }
353 };
354 
355 
359 class Condition final: public UnderlyingType<Condition, uv_cond_t> {
360 public:
361  explicit Condition(ConstructorAccess ca, std::shared_ptr<Loop> ref) noexcept
362  : UnderlyingType{ca, std::move(ref)}
363  {
364  uv_cond_init(get());
365  }
366 
367  ~Condition() noexcept {
368  uv_cond_destroy(get());
369  }
370 
377  void signal() noexcept {
378  uv_cond_signal(get());
379  }
380 
386  void broadcast() noexcept {
387  uv_cond_broadcast(get());
388  }
389 
399  void wait(Mutex &mutex) noexcept {
400  uv_cond_wait(get(), mutex.get());
401  }
402 
418  bool timedWait(Mutex &mutex, uint64_t timeout) noexcept {
419  return (0 == uv_cond_timedwait(get(), mutex.get(), timeout));
420  }
421 };
422 
423 
433 class Barrier final: public UnderlyingType<Barrier, uv_barrier_t> {
434 public:
435  explicit Barrier(ConstructorAccess ca, std::shared_ptr<Loop> ref, unsigned int count) noexcept
436  : UnderlyingType{ca, std::move(ref)}
437  {
438  uv_barrier_init(get(), count);
439  }
440 
441  ~Barrier() noexcept {
442  uv_barrier_destroy(get());
443  }
444 
449  bool wait() noexcept {
450  return (0 == uv_barrier_wait(get()));
451  }
452 };
453 
454 
455 }
bool wait() noexcept
Synchronizes at a barrier.
Definition: thread.hpp:449
The Barrier wrapper.
Definition: thread.hpp:433
void wait(Mutex &mutex) noexcept
Waits on a condition.
Definition: thread.hpp:399
void wait() noexcept
Locks a semaphore.
Definition: thread.hpp:342
void signal() noexcept
Signals a condition.
Definition: thread.hpp:377
Wrapper class for underlying types.
void unlock() noexcept
Unlocks the mutex.
Definition: thread.hpp:246
bool tryWrLock() noexcept
Tries to lock a read-write lock object for writing.
Definition: thread.hpp:300
The RWLock wrapper.
Definition: thread.hpp:255
void wrLock() noexcept
Locks a read-write lock object for writing.
Definition: thread.hpp:292
Utility class to handle flags.
Definition: util.hpp:82
The Mutex wrapper.
Definition: thread.hpp:210
bool timedWait(Mutex &mutex, uint64_t timeout) noexcept
Waits on a condition.
Definition: thread.hpp:418
bool tryLock() noexcept
Tries to lock the mutex.
Definition: thread.hpp:239
static bool equal(const Thread &tl, const Thread &tr) noexcept
Compares thread by means of their identifiers.
Definition: thread.hpp:79
void rdLock() noexcept
Locks a read-write lock object for reading.
Definition: thread.hpp:270
bool run() noexcept
Creates a new thread.
Definition: thread.hpp:91
The Condition wrapper.
Definition: thread.hpp:359
bool run(Flags< Options > opts, std::size_t stack={}) noexcept
Creates a new thread.
Definition: thread.hpp:108
bool join() noexcept
Joins with a terminated thread.
Definition: thread.hpp:117
void broadcast() noexcept
Broadcasts a condition.
Definition: thread.hpp:386
The Thread wrapper.
Definition: thread.hpp:48
static void once(F &&f) noexcept
Runs a function once and only once.
Definition: thread.hpp:193
bool tryRdLock() noexcept
Tries to lock a read-write lock object for reading.
Definition: thread.hpp:278
void lock() noexcept
Locks the mutex.
Definition: thread.hpp:231
void rdUnlock() noexcept
Unlocks a read-write lock object previously locked for reading.
Definition: thread.hpp:285
The Once wrapper.
Definition: thread.hpp:174
bool tryWait() noexcept
Tries to lock a semaphore.
Definition: thread.hpp:350
The Semaphore wrapper.
Definition: thread.hpp:320
void post() noexcept
Unlocks a semaphore.
Definition: thread.hpp:335
void wrUnlock() noexcept
Unlocks a read-write lock object previously locked for writing.
Definition: thread.hpp:307
The ThreadLocalStorage wrapper.
Definition: thread.hpp:134
uvw default namespace.
Definition: async.hpp:11