为什么 C++20 std::condition_variable 不支持 std::stop_token?
Why does C++20 std::condition_variable not support std::stop_token?
在 C++20 标准库中 std::condition_variable_any::wait()
系列支持 std::stop_token
通用线程取消,但 std::condition_variable
不支持。
P0660R10 Stop Token and Joining Thread, Rev 10 说:
New in R6
- User
condition_variable_any
instead of consition_variable
to avoid all possible races, deadlocks, and unintended undefined behavior.
我认为以下代码安全地模拟了 condition_variable::wait()
和 stop_token
取消。我错过了什么?是否存在微妙的边缘情况?
template<class Lock, class Predicate>
bool cv_wait_with_stoken(
std::condition_variable& cv, Lock& lock, std::stop_token stoken, Predicate pred)
{
std::stop_callback callback{ stoken, [&cv]{ cv.notify_all(); } };
while (!stoken.stop_requested()) {
if (pred())
return true;
cv.wait(lock);
}
return pred();
}
是的,存在竞争条件。
一般来说,对于条件变量,您必须在 修改保护状态(通常是变量)和向条件变量发出信号之间保持互斥体一段时间。如果不这样做,您可能会错过信号。
将您的状态设为原子变量并不能避免该问题。
cv 的等待代码首先检查状态。如果失败,它会自动删除锁并等待信号。
如果您的停止令牌在检查之后但在等待之前设置在该间隙中,则停止令牌调用通知所有,通知所有不会被条件变量拾取。
cv.notify_all()
必须先获得该锁。这打开了一整罐蠕虫。
不要使用此代码,它可能会由于双重锁定或无数其他原因而严重崩溃,但理论上它看起来像:
bool cv_wait_with_stoken(
std::condition_variable& cv,
Lock& lock,
std::stop_token stoken,
Predicate pred
) {
std::stop_callback callback{ stoken, [&cv]{
lock.lock();
lock.unlock();
cv.notify_all();
} };
while (!stoken.stop_requested()) {
if (pred())
return true;
cv.wait(lock);
}
return pred();
}
可能try_lock
那里,我将不得不做很多艰苦的证明工作。
在 C++20 标准库中 std::condition_variable_any::wait()
系列支持 std::stop_token
通用线程取消,但 std::condition_variable
不支持。
P0660R10 Stop Token and Joining Thread, Rev 10 说:
New in R6
- User
condition_variable_any
instead ofconsition_variable
to avoid all possible races, deadlocks, and unintended undefined behavior.
我认为以下代码安全地模拟了 condition_variable::wait()
和 stop_token
取消。我错过了什么?是否存在微妙的边缘情况?
template<class Lock, class Predicate>
bool cv_wait_with_stoken(
std::condition_variable& cv, Lock& lock, std::stop_token stoken, Predicate pred)
{
std::stop_callback callback{ stoken, [&cv]{ cv.notify_all(); } };
while (!stoken.stop_requested()) {
if (pred())
return true;
cv.wait(lock);
}
return pred();
}
是的,存在竞争条件。
一般来说,对于条件变量,您必须在 修改保护状态(通常是变量)和向条件变量发出信号之间保持互斥体一段时间。如果不这样做,您可能会错过信号。
将您的状态设为原子变量并不能避免该问题。
cv 的等待代码首先检查状态。如果失败,它会自动删除锁并等待信号。
如果您的停止令牌在检查之后但在等待之前设置在该间隙中,则停止令牌调用通知所有,通知所有不会被条件变量拾取。
cv.notify_all()
必须先获得该锁。这打开了一整罐蠕虫。
不要使用此代码,它可能会由于双重锁定或无数其他原因而严重崩溃,但理论上它看起来像:
bool cv_wait_with_stoken(
std::condition_variable& cv,
Lock& lock,
std::stop_token stoken,
Predicate pred
) {
std::stop_callback callback{ stoken, [&cv]{
lock.lock();
lock.unlock();
cv.notify_all();
} };
while (!stoken.stop_requested()) {
if (pred())
return true;
cv.wait(lock);
}
return pred();
}
可能try_lock
那里,我将不得不做很多艰苦的证明工作。