![](/img/trans.png)
[英]If there are many threads are waiting to be notify, which one does the std::condition_variable::notify_one() function notify?
[英]std::condition_variable::notify_one: does it wake multiple threads if some have false predicate?
我有一个用于读/写的环形缓冲区。 如果环形缓冲区中的条目,我会跟踪数字,并且不允许覆盖尚未读取的条目。 我使用 std::condition_variable wait() 和 notify_one() 来同步读取器和写入器。 基本上阅读器的条件是条目数> 0。写入器的条件是条目数<容量。
这一切似乎都有效,但有一件事我不明白。 当读取器或写入器调用 notify_one() 时,不会导致上下文切换。 我已经阅读并理解它是这样工作的。 但是,在写入者写入条目以填充缓冲区的情况下,写入者调用 notify_one() 并继续写入另一个,在这种情况下,其谓词在其 wait() 中失败。 在这种情况下,我看到另一个 writer() 可能会醒来,并且它的谓词也会失败。 然后阅读器将醒来并且其谓词成功并且可以开始阅读。
我不明白为什么在一个 notify_one() 多个线程被解除阻塞。 带有失败谓词的 wait() 不会吃掉通知吗? 我找不到任何说明这种情况的东西。
我可以调用 notify_all() 来确定,但它似乎正在使用 notify_one()。
这是代码。
#include <iostream>
#include <stdint.h>
#include <boost/circular_buffer.hpp>
#include <condition_variable>
#include <thread>
// ring buffer with protection for overwrites
template <typename T>
class ring_buffer {
public:
ring_buffer(size_t size) {
cb.set_capacity(size);
}
void read(T& entry) {
{
std::unique_lock<std::mutex> lk(cv_mutex);
cv.wait(lk, [this] {
std::cout << "read woke up, test=" << (cb.size() > 0) << std::endl;
return 0 < cb.size();});
auto iter = cb.begin();
entry = *iter;
cb.pop_front();
std::cout << "Read notify_one" << std::endl;
}
cv.notify_one();
}
void write(const T& entry) {
{
std::unique_lock<std::mutex> lk(cv_mutex);
//std::cout << "Write wait" << std::endl;
cv.wait(lk, [this] {
std::cout << "write woke up, test=" << (cb.size() < cb.capacity()) << std::endl;
return cb.size() < cb.capacity();});
cb.push_back(entry);
std::cout << "Write notify_one" << std::endl;
}
cv.notify_one();
}
size_t get_number_entries() {
std::unique_lock<std::mutex> lk(cv_mutex);
return cb.size();
}
private:
boost::circular_buffer<T> cb;
std::condition_variable cv;
std::mutex cv_mutex;
};
void write_loop(ring_buffer<int> *buffer) {
for (int i = 0; i < 100000; ++i) {
buffer->write(i);
}
}
void read_loop(ring_buffer<int> *buffer) {
for (int i = 0; i < 50000; ++i) {
int val;
buffer->read(val);
}
}
int main() {
ring_buffer<int> buffer(1000);
std::thread writer(write_loop, &buffer);
std::thread reader(read_loop, &buffer);
std::thread reader2(read_loop, &buffer);
writer.join();
reader.join();
reader2.join();
return 0;
}
我在 output 中看到以下内容,其中多个线程被唤醒,因为谓词为假。
read woke up, test=0
read woke up, test=0
write woke up, test=1
当您的每个读取线程检查它是否应该等待或条件是否已经满足时,您会看到条件的初始测试。
从这里开始,这个 wait() 的重载相当于
while (!pred()) {
wait(lock);
}
所以 wait() 仅在条件为true
时调用,但必须先检查条件。
read woke up, test=0 // tests condition on reader1 thread, false, wait is called
read woke up, test=0 // tests condition on reader2 thread, false, wait is called
write woke up, test=1 // tests condition on writer thread, true, wait is not called
这可能会使写入 2 个值的位置变得很明显,并且每个读取器只会读取一个值。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.