document generic_condvar
parent
90af651f24
commit
d5f2f7f6b7
|
@ -1,6 +1,12 @@
|
|||
/* A generic condvar that can store any other condvar as a single type.
|
||||
/** @addtogroup Concurrency
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @file generic_condvar.hh
|
||||
*
|
||||
* This file is part of OctaSTD. See COPYING.md for futher information.
|
||||
* A single type that can encapsulate different condvar types.
|
||||
*
|
||||
* @copyright See COPYING.md in the project tree for further information.
|
||||
*/
|
||||
|
||||
#ifndef OSTD_GENERIC_CONDVAR_HH
|
||||
|
@ -12,6 +18,10 @@
|
|||
|
||||
namespace ostd {
|
||||
|
||||
/** @addtogroup Concurrency
|
||||
* @{
|
||||
*/
|
||||
|
||||
namespace detail {
|
||||
struct cond_iface {
|
||||
cond_iface() {}
|
||||
|
@ -40,42 +50,113 @@ namespace detail {
|
|||
};
|
||||
} /* namespace detail */
|
||||
|
||||
/** @brief A generic condition variable type.
|
||||
*
|
||||
* This is a type that implements a condition variable interface but can
|
||||
* encapsulate different real condition variable types while still having
|
||||
* just one static type. This is useful when you need to implement a data
|
||||
* structure that requires a condition variable but still want it to be
|
||||
* compatible with custom schedulers (which can use a custom condition
|
||||
* variable implementation for their logical threads) without having to
|
||||
* template it.
|
||||
*
|
||||
* The storage for the custom type is at least 6 pointers, depending on
|
||||
* the size of a standard std::condition_variable (if it's bigger, the
|
||||
* space is the size of that).
|
||||
*/
|
||||
struct generic_condvar {
|
||||
/** Constructs the condvar using std::condition_variable. */
|
||||
generic_condvar() {
|
||||
new (reinterpret_cast<void *>(&p_condbuf))
|
||||
detail::cond_impl<std::condition_variable>();
|
||||
}
|
||||
|
||||
/** @brief Constructs the condvar using a custom type.
|
||||
*
|
||||
* As condvars don't have to be move constructible and your own
|
||||
* condvar type can internally contain some custom state, the
|
||||
* condvar to store is constructed using a function, which is
|
||||
* required to return it.
|
||||
*
|
||||
* @param[in] func The function that is called to get the condvar.
|
||||
*/
|
||||
template<typename F>
|
||||
generic_condvar(F &&func) {
|
||||
new (reinterpret_cast<void *>(&p_condbuf))
|
||||
detail::cond_impl<std::result_of_t<F()>>(func);
|
||||
}
|
||||
|
||||
/** Condvars are not copy constructible. */
|
||||
generic_condvar(generic_condvar const &) = delete;
|
||||
|
||||
/** Condvars are not move constructible. */
|
||||
generic_condvar(generic_condvar &&) = delete;
|
||||
|
||||
/** Condvars are not copy assignable. */
|
||||
generic_condvar &operator=(generic_condvar const &) = delete;
|
||||
|
||||
/** Condvars are not move assignable. */
|
||||
generic_condvar &operator=(generic_condvar &&) = delete;
|
||||
|
||||
/** Destroys the stored condvar. */
|
||||
~generic_condvar() {
|
||||
reinterpret_cast<detail::cond_iface *>(&p_condbuf)->~cond_iface();
|
||||
}
|
||||
|
||||
/** @brief Notifies one waiting thread.
|
||||
*
|
||||
* If any threads are waiting on this condvar, this unblocks one of
|
||||
* them. The actual semantics and what the threads are are defined by
|
||||
* the condition variable type that is stored. This simply calls
|
||||
* `.notify_one()` on the stored condvar.
|
||||
*
|
||||
* @see notify_all(), wait(std::unique_lock<std::mutex>)
|
||||
*/
|
||||
void notify_one() {
|
||||
reinterpret_cast<detail::cond_iface *>(&p_condbuf)->notify_one();
|
||||
}
|
||||
|
||||
/** @brief Notifies all waiting threads.
|
||||
*
|
||||
* If any threads are waiting on this condvar, this unblocks all of
|
||||
* them. The actual semantics and what the threads are are defined by
|
||||
* the condition variable type that is stored. This simply calls
|
||||
* `.notify_all()` on the stored condvar.
|
||||
*
|
||||
* @see notify_one(), wait(std::unique_lock<std::mutex>)
|
||||
*/
|
||||
void notify_all() {
|
||||
reinterpret_cast<detail::cond_iface *>(&p_condbuf)->notify_all();
|
||||
}
|
||||
|
||||
/** @brief Blocks the current thread until the condvar is woken up.
|
||||
*
|
||||
* This atomically releases the given lock, blocks the current thread
|
||||
* and adds it to the waiting threads list, until unblocked by notify_one()
|
||||
* or notify_all(). It may also be unblocked spuriously, depending on the
|
||||
* implementation. The actual specific semantics and what the current
|
||||
* thread is depends on the implementation of the stored condvar. This
|
||||
* simply calls `.wait(l)` on it.
|
||||
*
|
||||
* @see notify_one(), notify_all()
|
||||
*/
|
||||
void wait(std::unique_lock<std::mutex> &l) {
|
||||
reinterpret_cast<detail::cond_iface *>(&p_condbuf)->wait(l);
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr size_t cvars = sizeof(std::condition_variable);
|
||||
static constexpr size_t icvars =
|
||||
sizeof(detail::cond_impl<std::condition_variable>);
|
||||
std::aligned_storage_t<std::max(
|
||||
6 * sizeof(void *), sizeof(detail::cond_impl<std::condition_variable>)
|
||||
6 * sizeof(void *) + (icvars - cvars), icvars
|
||||
)> p_condbuf;
|
||||
};
|
||||
|
||||
/** @} */
|
||||
|
||||
} /* namespace ostd */
|
||||
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
|
|
@ -221,6 +221,6 @@ private:
|
|||
|
||||
} /* namespace ostd */
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
|
Loading…
Reference in New Issue