forked from OctaForge/libostd
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
|
#ifndef OSTD_GENERIC_CONDVAR_HH
|
||||||
|
@ -12,6 +18,10 @@
|
||||||
|
|
||||||
namespace ostd {
|
namespace ostd {
|
||||||
|
|
||||||
|
/** @addtogroup Concurrency
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
struct cond_iface {
|
struct cond_iface {
|
||||||
cond_iface() {}
|
cond_iface() {}
|
||||||
|
@ -40,42 +50,113 @@ namespace detail {
|
||||||
};
|
};
|
||||||
} /* 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 {
|
struct generic_condvar {
|
||||||
|
/** Constructs the condvar using std::condition_variable. */
|
||||||
generic_condvar() {
|
generic_condvar() {
|
||||||
new (reinterpret_cast<void *>(&p_condbuf))
|
new (reinterpret_cast<void *>(&p_condbuf))
|
||||||
detail::cond_impl<std::condition_variable>();
|
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>
|
template<typename F>
|
||||||
generic_condvar(F &&func) {
|
generic_condvar(F &&func) {
|
||||||
new (reinterpret_cast<void *>(&p_condbuf))
|
new (reinterpret_cast<void *>(&p_condbuf))
|
||||||
detail::cond_impl<std::result_of_t<F()>>(func);
|
detail::cond_impl<std::result_of_t<F()>>(func);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Condvars are not copy constructible. */
|
||||||
generic_condvar(generic_condvar const &) = delete;
|
generic_condvar(generic_condvar const &) = delete;
|
||||||
|
|
||||||
|
/** Condvars are not move constructible. */
|
||||||
generic_condvar(generic_condvar &&) = delete;
|
generic_condvar(generic_condvar &&) = delete;
|
||||||
|
|
||||||
|
/** Condvars are not copy assignable. */
|
||||||
generic_condvar &operator=(generic_condvar const &) = delete;
|
generic_condvar &operator=(generic_condvar const &) = delete;
|
||||||
|
|
||||||
|
/** Condvars are not move assignable. */
|
||||||
generic_condvar &operator=(generic_condvar &&) = delete;
|
generic_condvar &operator=(generic_condvar &&) = delete;
|
||||||
|
|
||||||
|
/** Destroys the stored condvar. */
|
||||||
~generic_condvar() {
|
~generic_condvar() {
|
||||||
reinterpret_cast<detail::cond_iface *>(&p_condbuf)->~cond_iface();
|
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() {
|
void notify_one() {
|
||||||
reinterpret_cast<detail::cond_iface *>(&p_condbuf)->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() {
|
void notify_all() {
|
||||||
reinterpret_cast<detail::cond_iface *>(&p_condbuf)->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) {
|
void wait(std::unique_lock<std::mutex> &l) {
|
||||||
reinterpret_cast<detail::cond_iface *>(&p_condbuf)->wait(l);
|
reinterpret_cast<detail::cond_iface *>(&p_condbuf)->wait(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
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(
|
std::aligned_storage_t<std::max(
|
||||||
6 * sizeof(void *), sizeof(detail::cond_impl<std::condition_variable>)
|
6 * sizeof(void *) + (icvars - cvars), icvars
|
||||||
)> p_condbuf;
|
)> p_condbuf;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
} /* namespace ostd */
|
} /* namespace ostd */
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
|
@ -221,6 +221,6 @@ private:
|
||||||
|
|
||||||
} /* namespace ostd */
|
} /* namespace ostd */
|
||||||
|
|
||||||
/** @} */
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
Loading…
Reference in New Issue