通知线程是否始终需要在修改期间锁定共享数据
Is it always necessary for a notifying thread to lock the shared data during modification?
使用条件变量时,http://en.cppreference.com/w/cpp/thread/condition_variable 描述了通知如下的线程的典型步骤:
- 获取 std::mutex(通常通过 std::lock_guard(
- 按住锁时执行修改
- 在 std::condition_variable 上执行notify_one或notify_all(无需按住锁进行通知(
对于下面显示的简单情况,主线程在修改时是否需要锁定"停止"?虽然我知道修改共享数据时锁定几乎总是一个好主意,但我不确定为什么在这种情况下有必要这样做。
std::condition_variable cv;
std::mutex mutex;
bool stop = false;
void worker() {
std::unique_lock<std::mutex> lock(mutex);
cv.wait(lock, [] { return stop; })
}
// No lock (Why would this not work?)
void main() {
std::thread(worker);
std::this_thread::sleep_for(1s);
stop = true;
cv.notify_one();
}
// With lock: why is this neccesary?
void main() {
std::thread mythread(worker);
std::this_thread::sleep_for(1s);
{
std::unique_lock<std::mutex>(mutex);
stop = true;
}
cv.notify_one();
mythread.join();
}
对于下面显示的简单情况,主线程在修改时是否需要锁定"停止"?
是的,以防止竞争条件。除了从不同线程访问共享数据的问题(可以通过std::atomic
修复(之外,想象一下以下事件顺序:
worker_thread: checks value of `stop` it is false
main_thread: sets `stop` to true and sends signal
worker_thread: sleeps on condition variable
在这种情况下,工作线程可能会永远休眠,并且它会错过stop
设置为true
的事件,仅仅是因为唤醒信号已经发送并且错过了它。
修改共享数据时需要获取互斥锁,因为只有这样,您才能将检查条件和进入睡眠状态或在工作线程中对其执行操作视为整个原子操作。
是 ,这是必要的。
首先,从标准的角度来看,您的代码表现出未定义的行为,因为stop
不是原子的,并且在锁下不会更改,而其他线程可能会读取或写入它。
如果多个线程读取和写入共享内存,则读取和写入都必须在锁下进行。
从硬件的角度来看,如果在锁下没有更改stop
,则其他线程(即使它们锁定了一些锁(也不能保证"看到"已完成的更改。 锁不仅可以防止其他线程干预,还可以强制将最新更改读取或写入主内存,因此所有线程都可以使用最新值。
相关文章:
- 使用C++库在Android项目中修改gradle中的cmake参数,用于插入指令的测试
- 独立读取-修改-写入顺序
- 当系统的卷被修改时,如何修改WASAPI环回捕获卷
- 修改函数中的指针(将另一个指针作为参数传递)
- 为什么我可以通过引用修改常量返回
- 对于结构,表达式必须是可修改的ivalue
- QML:修改在不同QML文件(而非main.QML)中定义的子对象的属性
- 为什么不能修改对象中的值?另外,我如何改进此链表?
- 修改创建帐户程序
- 我应该如何修改此代码以使用给定字符串中的字母打印菱形图案
- 如何从子成员函数修改父公共成员变量
- 修改 VS Code 中的默认C++代码段
- 为什么在我的函数类型后使用引用运算符 (&) 允许我修改它返回的值?
- 如何使用递归打印修改后的星号三角形图案
- 已修改的LinkedList未在文本文件本身中更新
- C++RapidXml-使用first_node()遍历以修改XML文件中节点的值
- 为什么可以修改数组 b?
- 将 C++ 类与 Rcpp 一起使用,从 C 或 R 修改它
- 修改的Fibbonaci C++得到一个大的负数
- clang 插件:在编译过程中修改 AST