TL;DR
为什么std::condition_variable::等待 http://en.cppreference.com/w/cpp/thread/condition_variable/wait需要互斥锁作为其变量之一吗?
Answer 1
您可以查看文档并引用:
wait... Atomically releases lock
但这不是真正的原因。这更加验证了我的问题:为什么它首先需要它?
Answer 2
谓词很可能查询共享资源的状态,并且必须受到锁保护。
好的。公平的。
这里有两个问题
- 总是这样吗谓词查询共享资源的状态?我想是的。否则对我来说实施它是没有意义的
- 如果我不传递任何谓词(它是可选的)怎么办?
使用谓词锁是有意义的
int i = 0;
void waits()
{
std::unique_lock<std::mutex> lk(cv_m);
cv.wait(lk, []{return i == 1;});
std::cout << i;
}
不使用谓词 - 为什么我们不能在等待后锁定?
int i = 0;
void waits()
{
cv.wait(lk);
std::unique_lock<std::mutex> lk(cv_m);
std::cout << i;
}
Notes
我知道这种做法不会产生有害影响。我只是不知道如何向自己解释为什么要这样设计?
Question
如果谓词是可选的并且未传递给wait
,为什么我们需要锁?
当使用条件变量等待条件时,线程执行以下步骤序列:
- 它确定条件当前不成立。
- 它开始等待其他线程使条件成立。这是
wait
call.
例如,条件可能是队列中有元素,并且线程可能会发现队列为空并等待另一个线程将元素放入队列中。
如果另一个线程要在这两个步骤之间进行调停,它可以使条件为真,并在第一个线程实际开始等待之前通知条件变量。在这种情况下,等待线程将不会收到通知,并且可能永远不会停止等待。
要求持有锁的目的是为了防止其他线程像这样介入。此外,必须解锁锁才能允许其他线程执行我们正在等待的任何操作,但这不能在wait
由于notify-before-wait问题而调用,并且在wait之后不可能发生wait
打电话是因为在等待期间我们无能为力。它必须是wait
打电话,所以wait
必须了解锁。
现在,您可能会看看notify_*
方法并注意those方法不需要持有锁,因此实际上没有什么可以阻止另一个线程在步骤 1 和 2 之间进行通知。但是,调用notify_*
应该在执行任何操作以使条件成立时保持锁定,这通常是足够的保护。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)