#include <ConditionVariable.h>
Public Types | |
using | MutexType = MUTEX |
using | ConditionVariableType = CONDITION_VARIABLE |
using | LockType = unique_lock< MUTEX > |
using | QuickLockType = lock_guard< MUTEX > |
Public Member Functions | |
nonvirtual void | release_and_notify_one (LockType &lock) noexcept |
nonvirtual void | release_and_notify_all (LockType &lock) noexcept |
nonvirtual void | notify_one () noexcept |
forward notify_one () call to underlying std::condition_variable' | |
nonvirtual void | notify_all () noexcept |
forward notify_all () call to underlying std::condition_variable' | |
nonvirtual cv_status | wait_until (LockType &lock, Time::TimePointSeconds timeoutAt) |
nonvirtual cv_status | wait_for (LockType &lock, Time::DurationSeconds timeout) |
template<invocable FUNCTION> | |
nonvirtual void | MutateDataNotifyAll (FUNCTION &&mutatorFunction) |
template<invocable FUNCTION> | |
nonvirtual void | MutateDataNotifyOne (FUNCTION &&mutatorFunction) |
Public Attributes | |
MutexType | fMutex |
CONDITION_VARIABLE | fConditionVariable |
Static Public Attributes | |
static Time::DurationSeconds | sConditionVariableWaitChunkTime {0.25s} |
NOTE - XCode 15 still has this limitation #if __cpp_lib_jthread < 201911 #warning "NOTE __cpp_lib_jthread < 201911: see if we can lose tests" #endif – LGP 2024-09-17 ConditionVariable is a thin abstraction/wrapper on a std::condition_variable, with support for Stroika thread Cancelation, and other shortcuts to simplify use. (combines related mutex with condition variable). Since you always use a condition variable with a mutex, its helpful to also include the associated mutex in the condition variable (type can be changed with template parameters).
Intentionally leave 'mutex' and 'condition_variable' elements public, because users will OFTEN need to directly access a reference to the mutex, and so there is little opportunity to hide.
This is just meant to codify some good practices and share some code. Its a VERY thin wrapper - if even that - on the std::mutex.
> Using EINTR (POSIX) and alertable states on windows - this is what we do most other places in Stroika for thread cancelability. Sadly, the POSIX (gcc/clang) of condition_variable don't appear to support EINTR, the windows implementation doesn't support alertable states, and (FIND REFERENCE***) I THINK I saw documented someplace the standard mentions that this cannot be done (no idea why) > Maintain a list of 'waiting' condition variables, and then have thread-abort notify_all() on each of these This significantly adds to the cost of waiting (add/remove safely from linked list with thread safety) - but that's probably still the best approach. Also have to code this very carefully to avoid deadlocks, since the cancelation code needs to lock something to allow it to safely signal the condition variable. ***Probably best approach but trickier todo*** > Just wake periodically (shorten the wait time) and look for aborts). This is arguably the most costly approach but also simplest to implement, and what we have for now (as of January 2018, version v2.0a225)
I believe this is because: The total ordering created by this pattern of update is crucial!
Thread A lock and then unlocks mutex, so change of state of triggered always BEFORE (or after) the change of state in the condition variable mutex, so no ambiguity about when fTriggered set.
If its set before, condition variable sees that on entry (in its pred check).
If its after, then on the mutex unlock (I DON'T KNOW HOW THIS HAPPENS YET) - the Condition var must somehow get 'awakened - probably by a TLS list (queue) of waiters to get notified and that gets hooked in the mutex code???? GUESSING.
So anyhow - note - its critical when changing values of underlying 'condition' - to wrap that in mutex lock/unlock.
This MAYBE related to why "std::condition_variable works only with std::unique_lock<std::mutex>". BUT - then i don't understand how " std::condition_variable_any provides a condition variable that works with any BasicLockable"
Definition at line 114 of file ConditionVariable.h.
using Stroika::Foundation::Execution::ConditionVariable< MUTEX, CONDITION_VARIABLE >::MutexType = MUTEX |
This is the type of the mutex associated with the condition variable.
Definition at line 118 of file ConditionVariable.h.
using Stroika::Foundation::Execution::ConditionVariable< MUTEX, CONDITION_VARIABLE >::ConditionVariableType = CONDITION_VARIABLE |
This is the type of condition variable. This is generally going to be condition_variable_any (so it will work with stop_tokens) but could be condition_variable (or others).
Definition at line 124 of file ConditionVariable.h.
using Stroika::Foundation::Execution::ConditionVariable< MUTEX, CONDITION_VARIABLE >::LockType = unique_lock<MUTEX> |
explicitly unlockable lock (on the mutex). Use, for example, with condition variables, where the apis need to unlock/lock and track the 'locked' state.
Definition at line 130 of file ConditionVariable.h.
using Stroika::Foundation::Execution::ConditionVariable< MUTEX, CONDITION_VARIABLE >::QuickLockType = lock_guard<MUTEX> |
just lock and unlock. Basically the same as LockType, but less flexible (cannot explicitly unlock) and more efficient (cuz no data to track if locked).
Definition at line 136 of file ConditionVariable.h.
|
noexcept |
NOTIFY the condition variable (notify_one), but unlock first due to:
http://en.cppreference.com/w/cpp/thread/condition_variable/notify_all
The notifying thread does not need to hold the lock on the same mutex as the one held by the waiting thread(s); in fact doing so is a pessimization, since the notified thread would immediately block again, waiting for the notifying thread to release the lock.
Definition at line 23 of file ConditionVariable.inl.
|
noexcept |
NOTIFY the condition variable (notify_all), but unlock first due to:
http://en.cppreference.com/w/cpp/thread/condition_variable/notify_all
The notifying thread does not need to hold the lock on the same mutex as the one held by the waiting thread(s); in fact doing so is a pessimization, since the notified thread would immediately block again, waiting for the notifying
Definition at line 29 of file ConditionVariable.inl.
|
noexcept |
forward notify_one () call to underlying std::condition_variable'
Definition at line 35 of file ConditionVariable.inl.
|
noexcept |
forward notify_all () call to underlying std::condition_variable'
Definition at line 40 of file ConditionVariable.inl.
cv_status Stroika::Foundation::Execution::ConditionVariable< MUTEX, CONDITION_VARIABLE >::wait_until | ( | LockType & | lock, |
Time::TimePointSeconds | timeoutAt | ||
) |
Like condition_variable wait_until, except using float instead of chrono (fix) supports Stroika thread interruption
readyToWake - predicate which returns false if the waiting should be continued.
Returns: 1) std::cv_status::timeout if the relative timeout specified by rel_time expired, std::cv_status::no_timeout otherwise. 2) true of 'readyToWake' () is reason we woke
Definition at line 45 of file ConditionVariable.inl.
cv_status Stroika::Foundation::Execution::ConditionVariable< MUTEX, CONDITION_VARIABLE >::wait_for | ( | LockType & | lock, |
Time::DurationSeconds | timeout | ||
) |
Like condition_variable wait_for, except using float instead of chrono (fix) supports Stroika thread interruption
readyToWake - predicate which returns false if the waiting should be continued.
Returns: 1) std::cv_status::timeout if the relative timeout specified by rel_time expired, std::cv_status::no_timeout otherwise. 2) true of 'readyToWake' () is reason we woke
Definition at line 165 of file ConditionVariable.inl.
nonvirtual void Stroika::Foundation::Execution::ConditionVariable< MUTEX, CONDITION_VARIABLE >::MutateDataNotifyAll | ( | FUNCTION && | mutatorFunction | ) |
Idea is you pass lambda to do actual data change, and this acquires lock first, and notifies all after.
nonvirtual void Stroika::Foundation::Execution::ConditionVariable< MUTEX, CONDITION_VARIABLE >::MutateDataNotifyOne | ( | FUNCTION && | mutatorFunction | ) |
Idea is you pass lambda to do actual data change, and this acquires lock first, and notifies one after.
|
static |
sConditionVariableWaitChunkTime is used iff kSupportsStopToken is false.
When waiting, with kSupportsStopToken false, this max timeout is used chunk the waits into smaller chunks so we can check for thread cancelation.
This time value is generally NOT used in condition variable operation, except in a few disparate situations: o stop_token overloads not supported (see kSupportsStopToken) o ? may change - cannot interrupt main thread (abort) so have no stop token to use/pass? why does that matter? \note in Stroika v2.1 this was called sThreadAbortCheckFrequency_Default
Definition at line 166 of file ConditionVariable.h.
MutexType Stroika::Foundation::Execution::ConditionVariable< MUTEX, CONDITION_VARIABLE >::fMutex |
ConditionVariable is a very THIN abstraction. Callers will often need to explicitly access/use the mutex
Definition at line 177 of file ConditionVariable.h.
CONDITION_VARIABLE Stroika::Foundation::Execution::ConditionVariable< MUTEX, CONDITION_VARIABLE >::fConditionVariable |
ConditionVariable is a very THIN abstraction. Callers will often need to explicitly access/use the condition_variable
Definition at line 182 of file ConditionVariable.h.