mirror of
https://github.com/boostorg/thread.git
synced 2026-01-27 19:32:11 +00:00
495 lines
16 KiB
Plaintext
495 lines
16 KiB
Plaintext
[section:condvar_ref Condition Variables]
|
|
|
|
[heading Synopsis]
|
|
|
|
The classes `condition_variable` and `condition_variable_any` provide a
|
|
mechanism for one thread to wait for notification from another thread that a
|
|
particular condition has become true. The general usage pattern is that one
|
|
thread locks a mutex and then calls `wait` on an instance of
|
|
`condition_variable` or `condition_variable_any`. When the thread is woken from
|
|
the wait, then it checks to see if the appropriate condition is now true, and
|
|
continues if so. If the condition is not true, then the thread then calls `wait`
|
|
again to resume waiting. In the simplest case, this condition is just a boolean
|
|
variable:
|
|
|
|
boost::condition_variable cond;
|
|
boost::mutex mut;
|
|
bool data_ready;
|
|
|
|
void process_data();
|
|
|
|
void wait_for_data_to_process()
|
|
{
|
|
boost::unique_lock<boost::mutex> lock(mut);
|
|
while(!data_ready)
|
|
{
|
|
cond.wait(lock);
|
|
}
|
|
process_data();
|
|
}
|
|
|
|
Notice that the `lock` is passed to `wait`: `wait` will atomically add the
|
|
thread to the set of threads waiting on the condition variable, and unlock the
|
|
mutex. When the thread is woken, the mutex will be locked again before the call
|
|
to `wait` returns. This allows other threads to acquire the mutex in order to
|
|
update the shared data, and ensures that the data associated with the condition
|
|
is correctly synchronized.
|
|
|
|
In the mean time, another thread sets the condition to `true`, and then calls
|
|
either `notify_one` or `notify_all` on the condition variable to wake one
|
|
waiting thread or all the waiting threads respectively.
|
|
|
|
void retrieve_data();
|
|
void prepare_data();
|
|
|
|
void prepare_data_for_processing()
|
|
{
|
|
retrieve_data();
|
|
prepare_data();
|
|
{
|
|
boost::lock_guard<boost::mutex> lock(mut);
|
|
data_ready=true;
|
|
}
|
|
cond.notify_one();
|
|
}
|
|
|
|
Note that the same mutex is locked before the shared data is updated, but that
|
|
the mutex does not have to be locked across the call to `notify_one`.
|
|
|
|
This example uses an object of type `condition_variable`, but would work just as
|
|
well with an object of type `condition_variable_any`: `condition_variable_any`
|
|
is more general, and will work with any kind of lock or mutex, whereas
|
|
`condition_variable` requires that the lock passed to `wait` is an instance of
|
|
`boost::unique_lock<boost::mutex>`. This enables `condition_variable` to make
|
|
optimizations in some cases, based on the knowledge of the mutex type;
|
|
`condition_variable_any` typically has a more complex implementation than
|
|
`condition_variable`.
|
|
|
|
[section:condition_variable Class `condition_variable`]
|
|
|
|
namespace boost
|
|
{
|
|
class condition_variable
|
|
{
|
|
public:
|
|
condition_variable();
|
|
~condition_variable();
|
|
|
|
void wait(boost::unique_lock<boost::mutex>& lock);
|
|
|
|
template<typename predicate_type>
|
|
void wait(boost::unique_lock<boost::mutex>& lock,predicate_type predicate);
|
|
|
|
bool timed_wait(boost::unique_lock<boost::mutex>& lock,boost::system_time const& abs_time);
|
|
|
|
template<typename duration_type>
|
|
bool timed_wait(boost::unique_lock<boost::mutex>& lock,duration_type const& rel_time);
|
|
|
|
template<typename predicate_type>
|
|
bool timed_wait(boost::unique_lock<boost::mutex>& lock,boost::system_time const& abs_time,predicate_type predicate);
|
|
|
|
template<typename duration_type,typename predicate_type>
|
|
bool timed_wait(boost::unique_lock<boost::mutex>& lock,duration_type const& rel_time,predicate_type predicate);
|
|
|
|
// backwards compatibility
|
|
|
|
bool timed_wait(boost::unique_lock<boost::mutex>& lock,boost::xtime const& abs_time);
|
|
|
|
template<typename predicate_type>
|
|
bool timed_wait(boost::unique_lock<boost::mutex>& lock,boost::xtime const& abs_time,predicate_type predicate);
|
|
};
|
|
}
|
|
|
|
[section:constructor `condition_variable()`]
|
|
|
|
[variablelist
|
|
|
|
[[Effects:] [Constructs an object of class `condition_variable`.]]
|
|
|
|
[[Throws:] [__thread_resource_error__ if an error occurs.]]
|
|
|
|
]
|
|
|
|
[endsect]
|
|
|
|
[section:destructor `~condition_variable()`]
|
|
|
|
[variablelist
|
|
|
|
[[Precondition:] [All threads waiting on `*this` have been notified by a call to
|
|
`notify_one` or `notify_all` (though the respective calls to `wait` or
|
|
`timed_wait` need not have returned).]]
|
|
|
|
[[Effects:] [Destroys the object.]]
|
|
|
|
[[Throws:] [Nothing.]]
|
|
|
|
]
|
|
|
|
[endsect]
|
|
|
|
[section:notify_one `void notify_one()`]
|
|
|
|
[variablelist
|
|
|
|
[[Effects:] [If any threads are currently __blocked__ waiting on `*this` in a call
|
|
to `wait` or `timed_wait`, unblocks one of those threads.]]
|
|
|
|
[[Throws:] [Nothing.]]
|
|
|
|
]
|
|
|
|
[endsect]
|
|
|
|
[section:notify_all `void notify_all()`]
|
|
|
|
[variablelist
|
|
|
|
[[Effects:] [If any threads are currently __blocked__ waiting on `*this` in a call
|
|
to `wait` or `timed_wait`, unblocks all of those threads.]]
|
|
|
|
[[Throws:] [Nothing.]]
|
|
|
|
]
|
|
|
|
[endsect]
|
|
|
|
[section:wait `void wait(boost::unique_lock<boost::mutex>& lock)`]
|
|
|
|
[variablelist
|
|
|
|
[[Precondition:] [`lock` is locked by the current thread, and either no other
|
|
thread is currently waiting on `*this`, or the execution of the `mutex()` member
|
|
function on the `lock` objects supplied in the calls to `wait` or `timed_wait`
|
|
in all the threads currently waiting on `*this` would return the same value as
|
|
`lock->mutex()` for this call to `wait`.]]
|
|
|
|
[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The
|
|
thread will unblock when notified by a call to `this->notify_one()` or
|
|
`this->notify_all()`, or spuriously. When the thread is unblocked (for whatever
|
|
reason), the lock is reacquired by invoking `lock.lock()` before the call to
|
|
`wait` returns. The lock is also reacquired by invoking `lock.lock()` if the
|
|
function exits with an exception.]]
|
|
|
|
[[Postcondition:] [`lock` is locked by the current thread.]]
|
|
|
|
[[Throws:] [__thread_resource_error__ if an error
|
|
occurs. __thread_interrupted__ if the wait was interrupted by a call to
|
|
__interrupt__ on the __thread__ object associated with the current thread of execution.]]
|
|
|
|
]
|
|
|
|
[endsect]
|
|
|
|
[section:wait_predicate `template<typename predicate_type> void wait(boost::unique_lock<boost::mutex>& lock, predicate_type pred)`]
|
|
|
|
[variablelist
|
|
|
|
[[Effects:] [As-if ``
|
|
while(!pred())
|
|
{
|
|
wait(lock);
|
|
}
|
|
``]]
|
|
|
|
]
|
|
|
|
[endsect]
|
|
|
|
[section:timed_wait `bool timed_wait(boost::unique_lock<boost::mutex>& lock,boost::system_time const& abs_time)`]
|
|
|
|
[variablelist
|
|
|
|
[[Precondition:] [`lock` is locked by the current thread, and either no other
|
|
thread is currently waiting on `*this`, or the execution of the `mutex()` member
|
|
function on the `lock` objects supplied in the calls to `wait` or `timed_wait`
|
|
in all the threads currently waiting on `*this` would return the same value as
|
|
`lock->mutex()` for this call to `wait`.]]
|
|
|
|
[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The
|
|
thread will unblock when notified by a call to `this->notify_one()` or
|
|
`this->notify_all()`, when the time as reported by `boost::get_system_time()`
|
|
would be equal to or later than the specified `abs_time`, or spuriously. When
|
|
the thread is unblocked (for whatever reason), the lock is reacquired by
|
|
invoking `lock.lock()` before the call to `wait` returns. The lock is also
|
|
reacquired by invoking `lock.lock()` if the function exits with an exception.]]
|
|
|
|
[[Returns:] [`false` if the call is returning because the time specified by
|
|
`abs_time` was reached, `true` otherwise.]]
|
|
|
|
[[Postcondition:] [`lock` is locked by the current thread.]]
|
|
|
|
[[Throws:] [__thread_resource_error__ if an error
|
|
occurs. __thread_interrupted__ if the wait was interrupted by a call to
|
|
__interrupt__ on the __thread__ object associated with the current thread of execution.]]
|
|
|
|
]
|
|
|
|
[endsect]
|
|
|
|
[section:timed_wait_rel `template<typename duration_type> bool timed_wait(boost::unique_lock<boost::mutex>& lock,duration_type const& rel_time)`]
|
|
|
|
[variablelist
|
|
|
|
[[Precondition:] [`lock` is locked by the current thread, and either no other
|
|
thread is currently waiting on `*this`, or the execution of the `mutex()` member
|
|
function on the `lock` objects supplied in the calls to `wait` or `timed_wait`
|
|
in all the threads currently waiting on `*this` would return the same value as
|
|
`lock->mutex()` for this call to `wait`.]]
|
|
|
|
[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The
|
|
thread will unblock when notified by a call to `this->notify_one()` or
|
|
`this->notify_all()`, after the period of time indicated by the `rel_time`
|
|
argument has elapsed, or spuriously. When the thread is unblocked (for whatever
|
|
reason), the lock is reacquired by invoking `lock.lock()` before the call to
|
|
`wait` returns. The lock is also reacquired by invoking `lock.lock()` if the
|
|
function exits with an exception.]]
|
|
|
|
[[Returns:] [`false` if the call is returning because the time period specified
|
|
by `rel_time` has elapsed, `true` otherwise.]]
|
|
|
|
[[Postcondition:] [`lock` is locked by the current thread.]]
|
|
|
|
[[Throws:] [__thread_resource_error__ if an error
|
|
occurs. __thread_interrupted__ if the wait was interrupted by a call to
|
|
__interrupt__ on the __thread__ object associated with the current thread of execution.]]
|
|
|
|
]
|
|
|
|
[note The duration overload of timed_wait is difficult to use correctly. The overload taking a predicate should be preferred in most cases.]
|
|
|
|
[endsect]
|
|
|
|
[section:timed_wait_predicate `template<typename predicate_type> bool timed_wait(boost::unique_lock<boost::mutex>& lock, boost::system_time const& abs_time, predicate_type pred)`]
|
|
|
|
[variablelist
|
|
|
|
[[Effects:] [As-if ``
|
|
while(!pred())
|
|
{
|
|
if(!timed_wait(lock,abs_time))
|
|
{
|
|
return pred();
|
|
}
|
|
}
|
|
return true;
|
|
``]]
|
|
|
|
]
|
|
|
|
[endsect]
|
|
|
|
|
|
[endsect]
|
|
|
|
[section:condition_variable_any Class `condition_variable_any`]
|
|
|
|
namespace boost
|
|
{
|
|
class condition_variable_any
|
|
{
|
|
public:
|
|
condition_variable_any();
|
|
~condition_variable_any();
|
|
|
|
template<typename lock_type>
|
|
void wait(lock_type& lock);
|
|
|
|
template<typename lock_type,typename predicate_type>
|
|
void wait(lock_type& lock,predicate_type predicate);
|
|
|
|
template<typename lock_type>
|
|
bool timed_wait(lock_type& lock,boost::system_time const& abs_time);
|
|
|
|
template<typename lock_type,typename duration_type>
|
|
bool timed_wait(lock_type& lock,duration_type const& rel_time);
|
|
|
|
template<typename lock_type,typename predicate_type>
|
|
bool timed_wait(lock_type& lock,boost::system_time const& abs_time,predicate_type predicate);
|
|
|
|
template<typename lock_type,typename duration_type,typename predicate_type>
|
|
bool timed_wait(lock_type& lock,duration_type const& rel_time,predicate_type predicate);
|
|
|
|
// backwards compatibility
|
|
|
|
template<typename lock_type>
|
|
bool timed_wait(lock_type>& lock,boost::xtime const& abs_time);
|
|
|
|
template<typename lock_type,typename predicate_type>
|
|
bool timed_wait(lock_type& lock,boost::xtime const& abs_time,predicate_type predicate);
|
|
};
|
|
}
|
|
|
|
[section:constructor `condition_variable_any()`]
|
|
|
|
[variablelist
|
|
|
|
[[Effects:] [Constructs an object of class `condition_variable_any`.]]
|
|
|
|
[[Throws:] [__thread_resource_error__ if an error occurs.]]
|
|
|
|
]
|
|
|
|
[endsect]
|
|
|
|
[section:destructor `~condition_variable_any()`]
|
|
|
|
[variablelist
|
|
|
|
[[Precondition:] [All threads waiting on `*this` have been notified by a call to
|
|
`notify_one` or `notify_all` (though the respective calls to `wait` or
|
|
`timed_wait` need not have returned).]]
|
|
|
|
[[Effects:] [Destroys the object.]]
|
|
|
|
[[Throws:] [Nothing.]]
|
|
|
|
]
|
|
|
|
[endsect]
|
|
|
|
[section:notify_one `void notify_one()`]
|
|
|
|
[variablelist
|
|
|
|
[[Effects:] [If any threads are currently __blocked__ waiting on `*this` in a call
|
|
to `wait` or `timed_wait`, unblocks one of those threads.]]
|
|
|
|
[[Throws:] [Nothing.]]
|
|
|
|
]
|
|
|
|
[endsect]
|
|
|
|
[section:notify_all `void notify_all()`]
|
|
|
|
[variablelist
|
|
|
|
[[Effects:] [If any threads are currently __blocked__ waiting on `*this` in a call
|
|
to `wait` or `timed_wait`, unblocks all of those threads.]]
|
|
|
|
[[Throws:] [Nothing.]]
|
|
|
|
]
|
|
|
|
[endsect]
|
|
|
|
[section:wait `template<typename lock_type> void wait(lock_type& lock)`]
|
|
|
|
[variablelist
|
|
|
|
[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The
|
|
thread will unblock when notified by a call to `this->notify_one()` or
|
|
`this->notify_all()`, or spuriously. When the thread is unblocked (for whatever
|
|
reason), the lock is reacquired by invoking `lock.lock()` before the call to
|
|
`wait` returns. The lock is also reacquired by invoking `lock.lock()` if the
|
|
function exits with an exception.]]
|
|
|
|
[[Postcondition:] [`lock` is locked by the current thread.]]
|
|
|
|
[[Throws:] [__thread_resource_error__ if an error
|
|
occurs. __thread_interrupted__ if the wait was interrupted by a call to
|
|
__interrupt__ on the __thread__ object associated with the current thread of execution.]]
|
|
|
|
]
|
|
|
|
[endsect]
|
|
|
|
[section:wait_predicate `template<typename lock_type,typename predicate_type> void wait(lock_type& lock, predicate_type pred)`]
|
|
|
|
[variablelist
|
|
|
|
[[Effects:] [As-if ``
|
|
while(!pred())
|
|
{
|
|
wait(lock);
|
|
}
|
|
``]]
|
|
|
|
]
|
|
|
|
[endsect]
|
|
|
|
[section:timed_wait `template<typename lock_type> bool timed_wait(lock_type& lock,boost::system_time const& abs_time)`]
|
|
|
|
[variablelist
|
|
|
|
[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The
|
|
thread will unblock when notified by a call to `this->notify_one()` or
|
|
`this->notify_all()`, when the time as reported by `boost::get_system_time()`
|
|
would be equal to or later than the specified `abs_time`, or spuriously. When
|
|
the thread is unblocked (for whatever reason), the lock is reacquired by
|
|
invoking `lock.lock()` before the call to `wait` returns. The lock is also
|
|
reacquired by invoking `lock.lock()` if the function exits with an exception.]]
|
|
|
|
[[Returns:] [`false` if the call is returning because the time specified by
|
|
`abs_time` was reached, `true` otherwise.]]
|
|
|
|
[[Postcondition:] [`lock` is locked by the current thread.]]
|
|
|
|
[[Throws:] [__thread_resource_error__ if an error
|
|
occurs. __thread_interrupted__ if the wait was interrupted by a call to
|
|
__interrupt__ on the __thread__ object associated with the current thread of execution.]]
|
|
|
|
]
|
|
|
|
[endsect]
|
|
|
|
[section:timed_wait_rel `template<typename lock_type,typename duration_type> bool timed_wait(lock_type& lock,duration_type const& rel_time)`]
|
|
|
|
[variablelist
|
|
|
|
[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The
|
|
thread will unblock when notified by a call to `this->notify_one()` or
|
|
`this->notify_all()`, after the period of time indicated by the `rel_time`
|
|
argument has elapsed, or spuriously. When the thread is unblocked (for whatever
|
|
reason), the lock is reacquired by invoking `lock.lock()` before the call to
|
|
`wait` returns. The lock is also reacquired by invoking `lock.lock()` if the
|
|
function exits with an exception.]]
|
|
|
|
[[Returns:] [`false` if the call is returning because the time period specified
|
|
by `rel_time` has elapsed, `true` otherwise.]]
|
|
|
|
[[Postcondition:] [`lock` is locked by the current thread.]]
|
|
|
|
[[Throws:] [__thread_resource_error__ if an error
|
|
occurs. __thread_interrupted__ if the wait was interrupted by a call to
|
|
__interrupt__ on the __thread__ object associated with the current thread of execution.]]
|
|
|
|
]
|
|
|
|
[note The duration overload of timed_wait is difficult to use correctly. The overload taking a predicate should be preferred in most cases.]
|
|
|
|
[endsect]
|
|
|
|
[section:timed_wait_predicate `template<typename lock_type,typename predicate_type> bool timed_wait(lock_type& lock, boost::system_time const& abs_time, predicate_type pred)`]
|
|
|
|
[variablelist
|
|
|
|
[[Effects:] [As-if ``
|
|
while(!pred())
|
|
{
|
|
if(!timed_wait(lock,abs_time))
|
|
{
|
|
return pred();
|
|
}
|
|
}
|
|
return true;
|
|
``]]
|
|
|
|
]
|
|
|
|
[endsect]
|
|
|
|
[endsect]
|
|
|
|
[section:condition Typedef `condition`]
|
|
|
|
typedef condition_variable_any condition;
|
|
|
|
The typedef `condition` is provided for backwards compatibility with previous boost releases.
|
|
|
|
[endsect]
|
|
|
|
[endsect]
|