在等待条件变量时,更改谓词状态的线程必须拥有锁,因此在唤醒期间不会错过更新。根据文档,这是必要的,即使在使用原子变量时也是如此。
但是我不确定 request_stop()
是否已经正确处理它。
所以问题是,这两个选项中哪一个是正确且符合标准的?
~jthread()
自然不会对 request_stop()
进行锁定,但是我不明白 stop_token< 之间的区别在哪里
和一个原子共享变量是。因此,其中一个需要锁,而另一个则不需要。
#include <thread>
#include <condition_variable>
#include <iostream>
#include <chrono>
std::mutex m;
std::condition_variable_any cv;
void waitingThread(std::stop_token st){
std::unique_lock<std::mutex> lk(m);
std::cout<<"Waiting"<<std::endl;
cv.wait(lk, st, [](){return false;});
std::cout<<"Awake"<<std::endl;
}
void withoutLock(){
std::jthread jt{waitingThread};
std::this_thread::sleep_for(std::chrono::seconds(1));
jt.request_stop();
}
void withLock(){
std::jthread jt{waitingThread};
std::this_thread::sleep_for(std::chrono::seconds(1));
{
std::lock_guard<std::mutex> lk(m);
jt.request_stop();
}
}
int main(){
withoutLock();
withLock();
}
Even if the shared variable is atomic, it must be modified while owning the mutex to correctly publish the modification to the waiting thread.
std::condition_variable_any::wait , std::stop_token 和 std::stop_source 不指定,如果等待的中断保证注册停止状态的变化。
最佳答案
While waiting on a condition variable, the thread changing the state of the predicate must own the lock, so the update isn't missed during the wakeup.
... do not specify, if the interrupt of the wait is guaranteed register the change in the stop state.
问题并不完全是缺少更新,而是在通知
发生之后、再次检查谓词之前返回 sleep 状态。
this answer中的序列是有问题的。
According to the documentation, this is necessary, even while using atomic variables. However I'm not certain if
request_stop()
already handles it correctly.
共享状态本身同步得很好:thread.stoptoken.intro/5说
Calls to the functions
request_stop
,stop_requested
, andstop_possible
do not introduce data races. A call torequest_stop
that returnstrue
synchronizes with a call tostop_requested
on an associatedstop_token
orstop_source
object that returns true.
thread.condvarany.intwait 中描述的等待谓词循环也会有同样的问题:
while (!stoken.stop_requested()) {
if (pred())
return true;
wait(lock);
}
return pred();
如果在第一行和 wait(lock)
之间调用 request_stop
,则 stop_requested()
将变为 true
并在无人等待时通知条件变量。然后我们将开始等待,等待永远不会到来的通知。
如果 request_stop
只能在 wait
内释放互斥锁时调用,我们将始终保证在之前检查 stop_requested()
又睡了。
事实上,GNU ISO C++ 库为我们做到了这一点:std::condition_variable_any
有一个额外的内部互斥体,用于同步 request_stop
回调(它只是通知请求线程中的 condvar)与等待谓词循环正确配合。因此,如果标准要求该行为,则您不需要自己的互斥体。
关于c++ - 在使用 stop_token 等待条件变量_any 时是否需要拥有锁来请求停止?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74601373/