c++ - 在使用 stop_token 等待条件变量_any 时是否需要拥有锁来请求停止?

标签 c++ multithreading concurrency stl condition-variable

在等待条件变量时,更改谓词状态的线程必须拥有锁,因此在唤醒期间不会错过更新。根据文档,这是必要的,即使在使用原子变量时也是如此。 但是我不确定 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();
}

std::condition_variable指定:

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_tokenstd::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, and stop_­possible do not introduce data races. A call to request_­stop that returns true synchronizes with a call to stop_­requested on an associated stop_­token or stop_­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/

相关文章:

java - 实现条件线程屏障的最佳方式

c++ - copy-and-swap 习语在 self 分配期间如何工作?

c++ - C++ 代码 `x.erase(std::remove(x.begin(), x.end(), ' '), x.end())` 是如何工作的?

c++将数据存储在对齐数组的中间

c - 如何使用 sem_trywait()?

c++ - 当 future 离开范围时,线程会去哪里?

java - 如何在并行流上使用java map-reduce组合器

并发原语测试用例

c++ - 比较次数和项目移动次数

java - 如何创建Rest API并增加处理时间?