2
0
mirror of https://github.com/boostorg/fiber.git synced 2026-02-15 00:52:34 +00:00

implement condition_variable in terms of condition_variable_any

This commit is contained in:
Oliver Kowalke
2015-12-18 07:38:42 +01:00
parent 550aed7c37
commit 117384d839
2 changed files with 106 additions and 21 deletions

View File

@@ -23,6 +23,7 @@
#include <boost/fiber/detail/spinlock.hpp>
#include <boost/fiber/exceptions.hpp>
#include <boost/fiber/interruption.hpp>
#include <boost/fiber/mutex.hpp>
#include <boost/fiber/operations.hpp>
#ifdef BOOST_HAS_ABI_HEADERS
@@ -34,7 +35,7 @@ namespace fibers {
using cv_status = std::cv_status;
class BOOST_FIBERS_DECL condition_variable {
class BOOST_FIBERS_DECL condition_variable_any {
private:
typedef context::wait_queue_t wait_queue_t;
@@ -42,33 +43,24 @@ private:
detail::spinlock wait_queue_splk_{};
public:
condition_variable() = default;
condition_variable_any() = default;
~condition_variable() {
~condition_variable_any() {
BOOST_ASSERT( wait_queue_.empty() );
}
condition_variable( condition_variable const&) = delete;
condition_variable & operator=( condition_variable const&) = delete;
condition_variable_any( condition_variable_any const&) = delete;
condition_variable_any & operator=( condition_variable_any const&) = delete;
void notify_one() noexcept;
void notify_all() noexcept;
template< typename LockType, typename Pred >
void wait( LockType & lt, Pred pred) {
while ( ! pred() ) {
wait( lt);
}
}
template< typename LockType >
void wait( LockType & lt) {
// check if context was interrupted
this_fiber::interruption_point();
context * ctx = context::active();
// pre-conditions
BOOST_ASSERT( lt.owns_lock() && ctx == lt.mutex()->owner_);
// atomically call lt.unlock() and block on *this
// store this fiber in waiting-queue
detail::spinlock_lock lk( wait_queue_splk_);
@@ -91,12 +83,18 @@ public:
std::terminate();
}
// post-conditions
BOOST_ASSERT( lt.owns_lock() && ctx == lt.mutex()->owner_);
BOOST_ASSERT( ! ctx->wait_is_linked() );
// check if context was interrupted
this_fiber::interruption_point();
}
template< typename LockType, typename Pred >
void wait( LockType & lt, Pred pred) {
while ( ! pred() ) {
wait( lt);
}
}
template< typename LockType, typename Clock, typename Duration >
cv_status wait_until( LockType & lt, std::chrono::time_point< Clock, Duration > const& timeout_time_) {
// check if context was interrupted
@@ -105,8 +103,6 @@ public:
std::chrono::steady_clock::time_point timeout_time(
detail::convert( timeout_time_) );
context * ctx = context::active();
// pre-conditions
BOOST_ASSERT( lt.owns_lock() && ctx == lt.mutex()->owner_);
// atomically call lt.unlock() and block on *this
// store this fiber in waiting-queue
detail::spinlock_lock lk( wait_queue_splk_);
@@ -131,7 +127,6 @@ public:
std::terminate();
}
// post-conditions
BOOST_ASSERT( lt.owns_lock() && ctx == lt.mutex()->owner_);
BOOST_ASSERT( ! ctx->wait_is_linked() );
// check if context was interrupted
this_fiber::interruption_point();
@@ -163,7 +158,97 @@ public:
}
};
using condition_variable_any = condition_variable;
class BOOST_FIBERS_DECL condition_variable {
private:
condition_variable_any cnd_;
public:
condition_variable() = default;
condition_variable( condition_variable const&) = delete;
condition_variable & operator=( condition_variable const&) = delete;
void notify_one() noexcept {
cnd_.notify_one();
}
void notify_all() noexcept {
cnd_.notify_all();
}
void wait( std::unique_lock< mutex > & lt) {
// pre-condition
BOOST_ASSERT( lt.owns_lock() );
BOOST_ASSERT( context::active() == lt.mutex()->owner_);
cnd_.wait( lt);
// post-condition
BOOST_ASSERT( lt.owns_lock() );
BOOST_ASSERT( context::active() == lt.mutex()->owner_);
}
template< typename Pred >
void wait( std::unique_lock< mutex > & lt, Pred pred) {
// pre-condition
BOOST_ASSERT( lt.owns_lock() );
BOOST_ASSERT( context::active() == lt.mutex()->owner_);
cnd_.wait( lt, pred);
// post-condition
BOOST_ASSERT( lt.owns_lock() );
BOOST_ASSERT( context::active() == lt.mutex()->owner_);
}
template< typename Clock, typename Duration >
cv_status wait_until( std::unique_lock< mutex > & lt,
std::chrono::time_point< Clock, Duration > const& timeout_time) {
// pre-condition
BOOST_ASSERT( lt.owns_lock() );
BOOST_ASSERT( context::active() == lt.mutex()->owner_);
cv_status result = cnd_.wait_until( lt, timeout_time);
// post-condition
BOOST_ASSERT( lt.owns_lock() );
BOOST_ASSERT( context::active() == lt.mutex()->owner_);
return result;
}
template< typename Clock, typename Duration, typename Pred >
bool wait_until( std::unique_lock< mutex > & lt,
std::chrono::time_point< Clock, Duration > const& timeout_time, Pred pred) {
// pre-condition
BOOST_ASSERT( lt.owns_lock() );
BOOST_ASSERT( context::active() == lt.mutex()->owner_);
bool result = cnd_.wait_until( lt, timeout_time, pred);
// post-condition
BOOST_ASSERT( lt.owns_lock() );
BOOST_ASSERT( context::active() == lt.mutex()->owner_);
return result;
}
template< typename Rep, typename Period >
cv_status wait_for( std::unique_lock< mutex > & lt,
std::chrono::duration< Rep, Period > const& timeout_duration) {
// pre-condition
BOOST_ASSERT( lt.owns_lock() );
BOOST_ASSERT( context::active() == lt.mutex()->owner_);
cv_status result = cnd_.wait_for( lt, timeout_duration);
// post-condition
BOOST_ASSERT( lt.owns_lock() );
BOOST_ASSERT( context::active() == lt.mutex()->owner_);
return result;
}
template< typename Rep, typename Period, typename Pred >
bool wait_for( std::unique_lock< mutex > & lt,
std::chrono::duration< Rep, Period > const& timeout_duration, Pred pred) {
// pre-condition
BOOST_ASSERT( lt.owns_lock() );
BOOST_ASSERT( context::active() == lt.mutex()->owner_);
bool result = cnd_.wait_for( lt, timeout_duration, pred);
// post-condition
BOOST_ASSERT( lt.owns_lock() );
BOOST_ASSERT( context::active() == lt.mutex()->owner_);
return result;
}
};
}}

View File

@@ -16,7 +16,7 @@ namespace boost {
namespace fibers {
void
condition_variable::notify_one() noexcept {
condition_variable_any::notify_one() noexcept {
// get one context' from wait-queue
detail::spinlock_lock lk( wait_queue_splk_);
if ( wait_queue_.empty() ) {
@@ -29,7 +29,7 @@ condition_variable::notify_one() noexcept {
}
void
condition_variable::notify_all() noexcept {
condition_variable_any::notify_all() noexcept {
// get all context' from wait-queue
detail::spinlock_lock lk( wait_queue_splk_);
// notify all context'