doc: thread.hpp
This commit is contained in:
parent
c053e861e8
commit
6b64e20161
@ -36,6 +36,15 @@ class Condition;
|
|||||||
class Barrier;
|
class Barrier;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The Thread wrapper.
|
||||||
|
*
|
||||||
|
* To create a `Thread` through a `Loop`, arguments follow:
|
||||||
|
*
|
||||||
|
* * A callback invoked to initialize thread execution. The type must be such
|
||||||
|
* that it can be assigned to an `std::function<void(std::shared_ptr<void>)>`.
|
||||||
|
* * An optional payload the type of which is `std::shared_ptr<void>`.
|
||||||
|
*/
|
||||||
class Thread final: public UnderlyingType<Thread, uv_thread_t> {
|
class Thread final: public UnderlyingType<Thread, uv_thread_t> {
|
||||||
using InternalTask = std::function<void(std::shared_ptr<void>)>;
|
using InternalTask = std::function<void(std::shared_ptr<void>)>;
|
||||||
|
|
||||||
@ -49,14 +58,24 @@ public:
|
|||||||
using Task = InternalTask;
|
using Task = InternalTask;
|
||||||
using Type = uv_thread_t;
|
using Type = uv_thread_t;
|
||||||
|
|
||||||
explicit Thread(ConstructorAccess ca, std::shared_ptr<Loop> ref, InternalTask t, std::shared_ptr<void> d = nullptr) noexcept
|
explicit Thread(ConstructorAccess ca, std::shared_ptr<Loop> ref, Task t, std::shared_ptr<void> d = nullptr) noexcept
|
||||||
: UnderlyingType{ca, std::move(ref)}, data{std::move(d)}, task{std::move(t)}
|
: UnderlyingType{ca, std::move(ref)}, data{std::move(d)}, task{std::move(t)}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Obtains the identifier of the calling thread.
|
||||||
|
* @return The identifier of the calling thread.
|
||||||
|
*/
|
||||||
static Type self() noexcept {
|
static Type self() noexcept {
|
||||||
return uv_thread_self();
|
return uv_thread_self();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Compares thread by means of their identifiers.
|
||||||
|
* @param tl A valid instance of a thread.
|
||||||
|
* @param tr A valid instance of a thread.
|
||||||
|
* @return True if the two threads are the same thread, false otherwise.
|
||||||
|
*/
|
||||||
static bool equal(const Thread &tl, const Thread &tr) noexcept {
|
static bool equal(const Thread &tl, const Thread &tr) noexcept {
|
||||||
return !(0 == uv_thread_equal(tl.get(), tr.get()));
|
return !(0 == uv_thread_equal(tl.get(), tr.get()));
|
||||||
}
|
}
|
||||||
@ -65,15 +84,36 @@ public:
|
|||||||
join();
|
join();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates a new thread.
|
||||||
|
* @return True in case of success, false otherwise.
|
||||||
|
*/
|
||||||
bool run() noexcept {
|
bool run() noexcept {
|
||||||
return (0 == uv_thread_create(get(), &createCallback, this));
|
return (0 == uv_thread_create(get(), &createCallback, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates a new thread.
|
||||||
|
*
|
||||||
|
* Available flags are:
|
||||||
|
*
|
||||||
|
* * `Thread::Options::THREAD_NO_FLAGS`: no flags set.
|
||||||
|
* * `Thread::Options::THREAD_HAS_STACK_SIZE`: if set, `stack` specifies a
|
||||||
|
* stack size for the new thread. 0 indicates that the default value should
|
||||||
|
* be used (it behaves as if the flag was not set). Other values will be
|
||||||
|
* rounded up to the nearest page boundary.
|
||||||
|
*
|
||||||
|
* @return True in case of success, false otherwise.
|
||||||
|
*/
|
||||||
bool run(Flags<Options> opts, std::size_t stack = {}) noexcept {
|
bool run(Flags<Options> opts, std::size_t stack = {}) noexcept {
|
||||||
uv_thread_options_t params{opts, stack};
|
uv_thread_options_t params{opts, stack};
|
||||||
return (0 == uv_thread_create_ex(get(), ¶ms, &createCallback, this));
|
return (0 == uv_thread_create_ex(get(), ¶ms, &createCallback, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Joins with a terminated thread.
|
||||||
|
* @return True in case of success, false otherwise.
|
||||||
|
*/
|
||||||
bool join() noexcept {
|
bool join() noexcept {
|
||||||
return (0 == uv_thread_join(get()));
|
return (0 == uv_thread_join(get()));
|
||||||
}
|
}
|
||||||
@ -84,6 +124,13 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The ThreadLocalStorage wrapper.
|
||||||
|
*
|
||||||
|
* A storage area that can only be accessed by one thread. The variable can be
|
||||||
|
* seen as a global variable that is only visible to a particular thread and not
|
||||||
|
* the whole program.
|
||||||
|
*/
|
||||||
class ThreadLocalStorage final: public UnderlyingType<ThreadLocalStorage, uv_key_t> {
|
class ThreadLocalStorage final: public UnderlyingType<ThreadLocalStorage, uv_key_t> {
|
||||||
public:
|
public:
|
||||||
explicit ThreadLocalStorage(ConstructorAccess ca, std::shared_ptr<Loop> ref) noexcept
|
explicit ThreadLocalStorage(ConstructorAccess ca, std::shared_ptr<Loop> ref) noexcept
|
||||||
@ -96,11 +143,21 @@ public:
|
|||||||
uv_key_delete(UnderlyingType::get());
|
uv_key_delete(UnderlyingType::get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the value of a given variable.
|
||||||
|
* @tparam T Type to which to cast the opaque storage area.
|
||||||
|
* @return A pointer to the given variable.
|
||||||
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T* get() noexcept {
|
T* get() noexcept {
|
||||||
return static_cast<T*>(uv_key_get(UnderlyingType::get()));
|
return static_cast<T*>(uv_key_get(UnderlyingType::get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the value of a given variable.
|
||||||
|
* @tparam T Type of the variable to store aside.
|
||||||
|
* @param value A valid pointer to the variable to store
|
||||||
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void set(T *value) noexcept {
|
void set(T *value) noexcept {
|
||||||
return uv_key_set(UnderlyingType::get(), value);
|
return uv_key_set(UnderlyingType::get(), value);
|
||||||
@ -108,7 +165,12 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// `Once` is an odd one as it doesn't use a `libuv` structure per object.
|
/**
|
||||||
|
* @brief The Once wrapper.
|
||||||
|
*
|
||||||
|
* Runs a function once and only once. Concurrent calls to `once` will block all
|
||||||
|
* callers except one (it’s unspecified which one).
|
||||||
|
*/
|
||||||
class Once final: public UnderlyingType<Once, uv_once_t> {
|
class Once final: public UnderlyingType<Once, uv_once_t> {
|
||||||
static uv_once_t* guard() noexcept {
|
static uv_once_t* guard() noexcept {
|
||||||
static uv_once_t once = UV_ONCE_INIT;
|
static uv_once_t once = UV_ONCE_INIT;
|
||||||
@ -118,9 +180,18 @@ class Once final: public UnderlyingType<Once, uv_once_t> {
|
|||||||
public:
|
public:
|
||||||
using UnderlyingType::UnderlyingType;
|
using UnderlyingType::UnderlyingType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Runs a function once and only once.
|
||||||
|
*
|
||||||
|
* The callback must be such that it's convertible to `void(*)(void)`. Free
|
||||||
|
* functions and non-capturing lambdas are both viable solutions.
|
||||||
|
*
|
||||||
|
* @tparam F Type of the callback.
|
||||||
|
* @param f A valid callback function.
|
||||||
|
*/
|
||||||
template<typename F>
|
template<typename F>
|
||||||
static void once(F &&f) noexcept {
|
static void once(F &&f) noexcept {
|
||||||
using CallbackType = void (*)(void);
|
using CallbackType = void(*)(void);
|
||||||
static_assert(std::is_convertible<F, CallbackType>::value, "!");
|
static_assert(std::is_convertible<F, CallbackType>::value, "!");
|
||||||
CallbackType cb = f;
|
CallbackType cb = f;
|
||||||
uv_once(guard(), cb);
|
uv_once(guard(), cb);
|
||||||
@ -128,6 +199,14 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The Mutex wrapper.
|
||||||
|
*
|
||||||
|
* To create a `Mutex` through a `Loop`, arguments follow:
|
||||||
|
*
|
||||||
|
* * An option boolean that specifies if the mutex is a recursive one. The
|
||||||
|
* default value is false, the mutex isn't recursive.
|
||||||
|
*/
|
||||||
class Mutex final: public UnderlyingType<Mutex, uv_mutex_t> {
|
class Mutex final: public UnderlyingType<Mutex, uv_mutex_t> {
|
||||||
friend class Condition;
|
friend class Condition;
|
||||||
|
|
||||||
@ -146,20 +225,33 @@ public:
|
|||||||
uv_mutex_destroy(get());
|
uv_mutex_destroy(get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Locks the mutex.
|
||||||
|
*/
|
||||||
void lock() noexcept {
|
void lock() noexcept {
|
||||||
uv_mutex_lock(get());
|
uv_mutex_lock(get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Tries to lock the mutex.
|
||||||
|
* @return True in case of success, false otherwise.
|
||||||
|
*/
|
||||||
bool tryLock() noexcept {
|
bool tryLock() noexcept {
|
||||||
return (0 == uv_mutex_trylock(get()));
|
return (0 == uv_mutex_trylock(get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unlocks the mutex.
|
||||||
|
*/
|
||||||
void unlock() noexcept {
|
void unlock() noexcept {
|
||||||
uv_mutex_unlock(get());
|
uv_mutex_unlock(get());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The RWLock wrapper.
|
||||||
|
*/
|
||||||
class RWLock final: public UnderlyingType<RWLock, uv_rwlock_t> {
|
class RWLock final: public UnderlyingType<RWLock, uv_rwlock_t> {
|
||||||
public:
|
public:
|
||||||
explicit RWLock(ConstructorAccess ca, std::shared_ptr<Loop> ref) noexcept
|
explicit RWLock(ConstructorAccess ca, std::shared_ptr<Loop> ref) noexcept
|
||||||
@ -172,32 +264,59 @@ public:
|
|||||||
uv_rwlock_destroy(get());
|
uv_rwlock_destroy(get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Locks a read-write lock object for reading.
|
||||||
|
*/
|
||||||
void rdLock() noexcept {
|
void rdLock() noexcept {
|
||||||
uv_rwlock_rdlock(get());
|
uv_rwlock_rdlock(get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Tries to lock a read-write lock object for reading.
|
||||||
|
* @return True in case of success, false otherwise.
|
||||||
|
*/
|
||||||
bool tryRdLock() noexcept {
|
bool tryRdLock() noexcept {
|
||||||
return (0 == uv_rwlock_tryrdlock(get()));
|
return (0 == uv_rwlock_tryrdlock(get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unlocks a read-write lock object previously locked for reading.
|
||||||
|
*/
|
||||||
void rdUnlock() noexcept {
|
void rdUnlock() noexcept {
|
||||||
uv_rwlock_rdunlock(get());
|
uv_rwlock_rdunlock(get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Locks a read-write lock object for writing.
|
||||||
|
*/
|
||||||
void wrLock() noexcept {
|
void wrLock() noexcept {
|
||||||
uv_rwlock_wrlock(get());
|
uv_rwlock_wrlock(get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Tries to lock a read-write lock object for writing.
|
||||||
|
* @return True in case of success, false otherwise.
|
||||||
|
*/
|
||||||
bool tryWrLock() noexcept {
|
bool tryWrLock() noexcept {
|
||||||
return (0 == uv_rwlock_trywrlock(get()));
|
return (0 == uv_rwlock_trywrlock(get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unlocks a read-write lock object previously locked for writing.
|
||||||
|
*/
|
||||||
void wrUnlock() noexcept {
|
void wrUnlock() noexcept {
|
||||||
uv_rwlock_wrunlock(get());
|
uv_rwlock_wrunlock(get());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The Semaphore wrapper.
|
||||||
|
*
|
||||||
|
* To create a `Semaphore` through a `Loop`, arguments follow:
|
||||||
|
*
|
||||||
|
* * An unsigned integer that specifies the initial value for the semaphore.
|
||||||
|
*/
|
||||||
class Semaphore final: public UnderlyingType<Semaphore, uv_sem_t> {
|
class Semaphore final: public UnderlyingType<Semaphore, uv_sem_t> {
|
||||||
public:
|
public:
|
||||||
explicit Semaphore(ConstructorAccess ca, std::shared_ptr<Loop> ref, unsigned int value) noexcept
|
explicit Semaphore(ConstructorAccess ca, std::shared_ptr<Loop> ref, unsigned int value) noexcept
|
||||||
@ -210,20 +329,33 @@ public:
|
|||||||
uv_sem_destroy(get());
|
uv_sem_destroy(get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unlocks a semaphore.
|
||||||
|
*/
|
||||||
void post() noexcept {
|
void post() noexcept {
|
||||||
uv_sem_post(get());
|
uv_sem_post(get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Locks a semaphore.
|
||||||
|
*/
|
||||||
void wait() noexcept {
|
void wait() noexcept {
|
||||||
uv_sem_wait(get());
|
uv_sem_wait(get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Tries to lock a semaphore.
|
||||||
|
* @return True in case of success, false otherwise.
|
||||||
|
*/
|
||||||
bool tryWait() noexcept {
|
bool tryWait() noexcept {
|
||||||
return (0 == uv_sem_trywait(get()));
|
return (0 == uv_sem_trywait(get()));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The Condition wrapper.
|
||||||
|
*/
|
||||||
class Condition final: public UnderlyingType<Condition, uv_cond_t> {
|
class Condition final: public UnderlyingType<Condition, uv_cond_t> {
|
||||||
public:
|
public:
|
||||||
explicit Condition(ConstructorAccess ca, std::shared_ptr<Loop> ref) noexcept
|
explicit Condition(ConstructorAccess ca, std::shared_ptr<Loop> ref) noexcept
|
||||||
@ -236,24 +368,68 @@ public:
|
|||||||
uv_cond_destroy(get());
|
uv_cond_destroy(get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Signals a condition.
|
||||||
|
*
|
||||||
|
* This function shall unblock at least one of the threads that are blocked
|
||||||
|
* on the specified condition variable (if any threads are blocked on it).
|
||||||
|
*/
|
||||||
void signal() noexcept {
|
void signal() noexcept {
|
||||||
uv_cond_signal(get());
|
uv_cond_signal(get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Broadcasts a condition.
|
||||||
|
*
|
||||||
|
* This function shall unblock threads blocked on a condition variable.
|
||||||
|
*/
|
||||||
void broadcast() noexcept {
|
void broadcast() noexcept {
|
||||||
uv_cond_broadcast(get());
|
uv_cond_broadcast(get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Waits on a condition.
|
||||||
|
*
|
||||||
|
* These function atomically releases the mutex and causes the calling
|
||||||
|
* thread to block on the condition variable.
|
||||||
|
*
|
||||||
|
* @param mutex A mutex locked by the calling thread, otherwise expect
|
||||||
|
* undefined behavior.
|
||||||
|
*/
|
||||||
void wait(Mutex &mutex) noexcept {
|
void wait(Mutex &mutex) noexcept {
|
||||||
uv_cond_wait(get(), mutex.get());
|
uv_cond_wait(get(), mutex.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Waits on a condition.
|
||||||
|
*
|
||||||
|
* These function atomically releases the mutex and causes the calling
|
||||||
|
* thread to block on the condition variable.<br/>
|
||||||
|
* The functions returns with an error if the absolute time specified passes
|
||||||
|
* (that is, system time equals or exceeds it) before the condition is
|
||||||
|
* signaled or broadcasted, or if the absolute time specified has already
|
||||||
|
* been passed at the time of the call.
|
||||||
|
*
|
||||||
|
* @param mutex A mutex locked by the calling thread, otherwise expect
|
||||||
|
* undefined behavior.
|
||||||
|
* @param timeout The maximum time to wait before to return.
|
||||||
|
* @return True in case of success, false otherwise.
|
||||||
|
*/
|
||||||
bool timedWait(Mutex &mutex, uint64_t timeout) noexcept {
|
bool timedWait(Mutex &mutex, uint64_t timeout) noexcept {
|
||||||
return (0 == uv_cond_timedwait(get(), mutex.get(), timeout));
|
return (0 == uv_cond_timedwait(get(), mutex.get(), timeout));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The Barrier wrapper.
|
||||||
|
*
|
||||||
|
* To create a `Barrier` through a `Loop`, arguments follow:
|
||||||
|
*
|
||||||
|
* * An unsigned integer that specifies the number of threads that must call
|
||||||
|
* `wait` before any of them successfully return from the call. The value
|
||||||
|
* specified must be greater than zero.
|
||||||
|
*/
|
||||||
class Barrier final: public UnderlyingType<Barrier, uv_barrier_t> {
|
class Barrier final: public UnderlyingType<Barrier, uv_barrier_t> {
|
||||||
public:
|
public:
|
||||||
explicit Barrier(ConstructorAccess ca, std::shared_ptr<Loop> ref, unsigned int count) noexcept
|
explicit Barrier(ConstructorAccess ca, std::shared_ptr<Loop> ref, unsigned int count) noexcept
|
||||||
@ -266,6 +442,10 @@ public:
|
|||||||
uv_barrier_destroy(get());
|
uv_barrier_destroy(get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Synchronizes at a barrier.
|
||||||
|
* @return True in case of success, false otherwise.
|
||||||
|
*/
|
||||||
bool wait() noexcept {
|
bool wait() noexcept {
|
||||||
return (0 == uv_barrier_wait(get()));
|
return (0 == uv_barrier_wait(get()));
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user