std::condition_variable::wait() 如何评估给定的谓词?
How does std::condition_variable::wait() evaluate the given predicate?
上下文:
在我能看到的关于 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()
如何评估谓词以确保它是线程安全的?
我的想法:
我想到了两种可能:
- )要么,谓词保证被原子评估(我从来没有读过这样的东西,因此我的问题)
- ) 或者,当发送 notify 信号时,
std::condition_variable::wait()
函数在 评估谓词之前重新获取互斥量 。
在点 2.) 的情况下,如果修改 i
(并调用 std::condition_variable::notify_one()
)的线程锁定mutex m
这样做之前。
例如:
void modify_func()
{
{
std::scoped_lock<std::mutex> lk(m); // Acquire the mutex
i += 1; // Modify i
} // Release the mutex
cv.notify_one();
}
当然,还有一种可能是我的理解完全错误,然后就没抓住重点了。
无论如何,我真的很惊讶我在文档中找不到任何关于它的细节。
你的第二种选择是正确的。如 cppreference 所述,谓词重载表现为
while (!pred()) {
wait(lock);
}
会,wait(lock)
总是在返回前重新上锁。请参阅 C++17 标准(草案 N4659)的 [thred.condition.condvar]/12 and predicate overload behavior in [thread.condition.condvar]/15 中的 wait
后置条件。
是的,在修改 i
时必须锁定互斥量,即使它是原子的。参见例如this question.
上下文:
在我能看到的关于 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()
如何评估谓词以确保它是线程安全的?
我的想法:
我想到了两种可能:
- )要么,谓词保证被原子评估(我从来没有读过这样的东西,因此我的问题)
- ) 或者,当发送 notify 信号时,
std::condition_variable::wait()
函数在 评估谓词之前重新获取互斥量 。
在点 2.) 的情况下,如果修改 i
(并调用 std::condition_variable::notify_one()
)的线程锁定mutex m
这样做之前。
例如:
void modify_func()
{
{
std::scoped_lock<std::mutex> lk(m); // Acquire the mutex
i += 1; // Modify i
} // Release the mutex
cv.notify_one();
}
当然,还有一种可能是我的理解完全错误,然后就没抓住重点了。
无论如何,我真的很惊讶我在文档中找不到任何关于它的细节。
你的第二种选择是正确的。如 cppreference 所述,谓词重载表现为
while (!pred()) {
wait(lock);
}
会,wait(lock)
总是在返回前重新上锁。请参阅 C++17 标准(草案 N4659)的 [thred.condition.condvar]/12 and predicate overload behavior in [thread.condition.condvar]/15 中的 wait
后置条件。
是的,在修改 i
时必须锁定互斥量,即使它是原子的。参见例如this question.