doc: thread.hpp

This commit is contained in:
Michele Caini 2019-03-09 23:44:02 +01:00
parent c053e861e8
commit 6b64e20161

View File

@ -36,6 +36,15 @@ class Condition;
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> {
using InternalTask = std::function<void(std::shared_ptr<void>)>;
@ -49,14 +58,24 @@ public:
using Task = InternalTask;
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)}
{}
/**
* @brief Obtains the identifier of the calling thread.
* @return The identifier of the calling thread.
*/
static Type self() noexcept {
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 {
return !(0 == uv_thread_equal(tl.get(), tr.get()));
}
@ -65,15 +84,36 @@ public:
join();
}
/**
* @brief Creates a new thread.
* @return True in case of success, false otherwise.
*/
bool run() noexcept {
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 {
uv_thread_options_t params{opts, stack};
return (0 == uv_thread_create_ex(get(), &params, &createCallback, this));
}
/**
* @brief Joins with a terminated thread.
* @return True in case of success, false otherwise.
*/
bool join() noexcept {
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> {
public:
explicit ThreadLocalStorage(ConstructorAccess ca, std::shared_ptr<Loop> ref) noexcept
@ -96,11 +143,21 @@ public:
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>
T* get() noexcept {
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>
void set(T *value) noexcept {
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 (its unspecified which one).
*/
class Once final: public UnderlyingType<Once, uv_once_t> {
static uv_once_t* guard() noexcept {
static uv_once_t once = UV_ONCE_INIT;
@ -118,9 +180,18 @@ class Once final: public UnderlyingType<Once, uv_once_t> {
public:
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>
static void once(F &&f) noexcept {
using CallbackType = void (*)(void);
using CallbackType = void(*)(void);
static_assert(std::is_convertible<F, CallbackType>::value, "!");
CallbackType cb = f;
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> {
friend class Condition;
@ -146,20 +225,33 @@ public:
uv_mutex_destroy(get());
}
/**
* @brief Locks the mutex.
*/
void lock() noexcept {
uv_mutex_lock(get());
}
/**
* @brief Tries to lock the mutex.
* @return True in case of success, false otherwise.
*/
bool tryLock() noexcept {
return (0 == uv_mutex_trylock(get()));
}
/**
* @brief Unlocks the mutex.
*/
void unlock() noexcept {
uv_mutex_unlock(get());
}
};
/**
* @brief The RWLock wrapper.
*/
class RWLock final: public UnderlyingType<RWLock, uv_rwlock_t> {
public:
explicit RWLock(ConstructorAccess ca, std::shared_ptr<Loop> ref) noexcept
@ -172,32 +264,59 @@ public:
uv_rwlock_destroy(get());
}
/**
* @brief Locks a read-write lock object for reading.
*/
void rdLock() noexcept {
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 {
return (0 == uv_rwlock_tryrdlock(get()));
}
/**
* @brief Unlocks a read-write lock object previously locked for reading.
*/
void rdUnlock() noexcept {
uv_rwlock_rdunlock(get());
}
/**
* @brief Locks a read-write lock object for writing.
*/
void wrLock() noexcept {
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 {
return (0 == uv_rwlock_trywrlock(get()));
}
/**
* @brief Unlocks a read-write lock object previously locked for writing.
*/
void wrUnlock() noexcept {
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> {
public:
explicit Semaphore(ConstructorAccess ca, std::shared_ptr<Loop> ref, unsigned int value) noexcept
@ -210,20 +329,33 @@ public:
uv_sem_destroy(get());
}
/**
* @brief Unlocks a semaphore.
*/
void post() noexcept {
uv_sem_post(get());
}
/**
* @brief Locks a semaphore.
*/
void wait() noexcept {
uv_sem_wait(get());
}
/**
* @brief Tries to lock a semaphore.
* @return True in case of success, false otherwise.
*/
bool tryWait() noexcept {
return (0 == uv_sem_trywait(get()));
}
};
/**
* @brief The Condition wrapper.
*/
class Condition final: public UnderlyingType<Condition, uv_cond_t> {
public:
explicit Condition(ConstructorAccess ca, std::shared_ptr<Loop> ref) noexcept
@ -236,24 +368,68 @@ public:
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 {
uv_cond_signal(get());
}
/**
* @brief Broadcasts a condition.
*
* This function shall unblock threads blocked on a condition variable.
*/
void broadcast() noexcept {
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 {
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 {
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> {
public:
explicit Barrier(ConstructorAccess ca, std::shared_ptr<Loop> ref, unsigned int count) noexcept
@ -266,6 +442,10 @@ public:
uv_barrier_destroy(get());
}
/**
* @brief Synchronizes at a barrier.
* @return True in case of success, false otherwise.
*/
bool wait() noexcept {
return (0 == uv_barrier_wait(get()));
}