【问题标题】:How does std::condition_variable::wait() evaluate the given predicate?std::condition_variable::wait() 如何评估给定的谓词?
【发布时间】:2020-02-25 09:36:15
【问题描述】:

上下文:

在我看到的关于使用std::condition_variable::wait() 的每个示例中,包括来自cppreference.com 的示例,从来没有任何同步机制用于保护谓词评估免受数据竞争的影响。

例如:

std::mutex m;
std::condition_variable cv;
int i = 0;

void waiting_func()
{
    std::unique_lock<std::mutex> lk(m);
    cv.wait(lk, [](){return i > 0;}); // No lock/unlock around the access of the global and shared variable i.
    // ...
}

问题:

如果没有这样的同步,即使来自有信誉的来源的例子,我猜那是因为没有必要。
但我想知道为什么? std::condition_variable::wait() 如何评估谓词使其是线程安全的?

我的想法:

我想出了两种可能:

  1. ) 要么,谓词保证被原子评估(我从未读过这样的东西,因此我的问题)
  2. ) 或者,当发送 notify 信号时,std::condition_variable::wait() 函数会在 评估谓词之前重新获取互斥锁。

在 2.) 点的情况下,如果修改i(并调用std::condition_variable::notify_one())的线程在这样做之前锁定互斥锁m,则可能是安全的。

例如:

void modify_func()
{
    {
        std::scoped_lock<std::mutex> lk(m); // Acquire the mutex
        i += 1;                             // Modify i
    }                                       // Release the mutex
    cv.notify_one();
}

当然,还有一种可能是我的理解是完全错误的,当时我没抓住重点。

无论如何,我真的很惊讶我在文档中找不到任何关于它的详细信息。

【问题讨论】:

标签: c++ predicate condition-variable


【解决方案1】:

您的第二种选择是正确的。如cppreference 所述,谓词重载表现为

while (!pred()) {
    wait(lock);
}

并且wait(lock) 总是在返回之前重新锁定。请参阅 C++17 标准(草案 N4659)的 [thred.condition.condvar]/12 中的 wait 后置条件和 [thread.condition.condvar]/15 中的谓词重载行为。

是的,在修改i 时必须锁定互斥锁,即使它是原子的。参见例如this question.

【讨论】:

  • 谢谢,我对这个sn-p关注不够。 +1 说明无论如何需要锁定原子变量(用作谓词)。
猜你喜欢
  • 1970-01-01
  • 2019-01-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-01
  • 1970-01-01
  • 2018-03-01
相关资源
最近更新 更多