wait/notify 在 unique_lock 互斥量上使用 wait/notify 是否安全?

Is it safe to wait/notify on unique_lock mutexes when same mutexes are used with lock_guard on somewhere else?

我正在使用以下一种 wait/signal 方式让线程相互通知。

std::condition_variable condBiz;
std::mutex mutexBar;
..
void Foo::wait()
{
    std::unique_lock<std::mutex> waitPoint(mutexBar);
    if (waitPoint.owns_lock())
    {
        condBiz.wait(waitPoint);
    }
}
void Foo::signal()
{
    std::unique_lock<std::mutex> waitPoint(mutexBar);
    condBiz.notify_all();
}
void Foo::safeSection(std::function<void(void)> & f)
{
   std::unique_lock<std::mutex> waitPoint(mutexBar); 
   f();
}

然后将 lock/unlock 机制从 unique_lock 转换为 lock_guard 因为我不会返回 unique_lock 在其他地方使用(wait/signal 除外)并且lock_guard据说开销更少:

void Foo::safeSection(std::function<void(void)> & f)
{
   std::lock_guard<std::mutex> waitPoint(mutexBar);  // same mutex object
   f();
}

而且有效。

这适用于所有平台还是看起来适用于当前平台? unique_lock 和 lock_guard 可以使用相同的互斥对象相互协作吗?

在您的 post 的评论中已经指出,检查 unique_lock 是否在 Foo::wait() 中拥有是没有意义的,因为关联的互斥量必须由在该点锁定以便线程继续进行。

相反,你的条件变量应该检查一些有意义的条件,它应该在 while 循环中或通过使用 condition_variable::wait 的重载来检查一些有意义的条件,它需要一个谓词作为它的第二个参数,这是C++ 标准的效果如下:

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

在 while 循环中检查谓词的原因是,除了条件可能已经满足因此无需等待之外,条件变量可能会虚假地唤醒,即使没有发出这样做的信号。

除此之外,信号线程没有理由不对关联的互斥体使用 lock_guard。但是我不清楚你想做什么。

两者都std::unique_lock and std::lock_guard在构造函数中锁定关联的互斥量并在析构函数中解锁它。

std::unique_lock:

Member functions

(constructor) constructs a unique_lock, optionally locking the supplied mutex
(destructor) unlocks the associated mutex, if owned

std::lock_guard 相同:

Member functions

(constructor) constructs a lock_guard, optionally locking the given mutex
(destructor) destructs the lock_guard object, unlocks the underlying mutex

由于两者的行为相同,当用作 RAII 样式包装器时,我认为将它们一起使用没有任何障碍,即使使用相同的互斥体。