Multithreading 如何很好地同步?

Multithreading 如何很好地同步?,multithreading,c++11,mutex,condition-variable,Multithreading,C++11,Mutex,Condition Variable,给定以下C++11代码片段: #include <condition_variable> #include <mutex> std::mutex block; long count; std::condition_variable cv; void await() { std::unique_lock<std::mutex> lk(block); if (count > 0) cv.wait(lk); } void c

给定以下C++11代码片段:

#include <condition_variable>
#include <mutex>
std::mutex block;
long count;
std::condition_variable cv;

void await()
{
    std::unique_lock<std::mutex> lk(block);
    if (count > 0)
        cv.wait(lk);
}

void countDown()
{
    std::lock_guard<std::mutex> lk(block);
    if (count > 0)
    {
        count--;
        if (count==0) cv.notify_all();
    }
}
#包括
#包括
std::互斥块;
长计数;
std::条件变量cv;
无效等待()
{
std::唯一锁lk(块);
如果(计数>0)
cv.等待(lk);
}
无效倒计时()
{
标准:锁紧装置lk(块);
如果(计数>0)
{
计数--;
如果(计数=0)cv.notify_all();
}
}
如果不清楚我试图完成什么,我希望调用等待暂停调用线程,而计数大于0,如果它已经减少到零,那么它就不应该暂停。其他线程可能会调用countDown(),这将唤醒以前调用wait的所有线程

上面的代码似乎在我尝试过的所有情况下都能工作,但我对此有一个令人不安的疑问,因为在我看来,如果调用wait()的线程恰好在其条件测试被评估之后,线程被cv.wait()调用实际挂起之前立即被抢占,如果此时正在调用倒计时函数,且计数等于0,那么它将向条件变量发出通知,如果它实际上已经在等待它。。。但是调用wait的线程还没有到达cv.wait()调用,因此当调用wait的线程恢复时,它会在cv.wait()调用处停止并无限期地等待


实际上,我还没有在实践中看到这种情况发生,但我想针对可能发生的情况强化代码。

考虑这些可能性是件好事。但在这种情况下,您的代码是正确和安全的

如果
wait
在其条件测试被评估后立即被抢占,并且就在cv.wait()调用实际挂起线程之前,如果此时正在调用倒计时函数,后一个线程将在尝试获取
block
互斥时阻塞,直到
wait
实际调用
cv.wait(lk)

调用
cv.wait(lk)
会隐式释放
block
上的锁,因此现在另一个线程可以在
倒计时()中获得
block
上的锁。只要线程在
countDown()
中持有
block
上的锁(即使在调用
cv.notify\u all()
之后,
wait
线程也不能从
cv.wait()
返回。
wait
线程在从
cv.wait()

更新

虽然
,但我在查看您的代码时确实犯了一个新手错误

cv.wait(lk)
可能会错误返回。也就是说,它可能会返回,即使它尚未得到通知。为了防止这种情况,您应该将
wait
置于while循环下,而不是if:

void await()
{
    std::unique_lock<std::mutex> lk(block);
    while (count > 0)
        cv.wait(lk);
}
void wait()
{
std::唯一锁lk(块);
而(计数>0)
cv.等待(lk);
}

现在,如果等待错误地返回,它将重新检查条件,如果仍然不满足,则再次等待。

您最好考虑这些可能性。但在这种情况下,您的代码是正确和安全的

如果
wait
在其条件测试被评估后立即被抢占,并且就在cv.wait()调用实际挂起线程之前,如果此时正在调用倒计时函数,后一个线程将在尝试获取
block
互斥时阻塞,直到
wait
实际调用
cv.wait(lk)

调用
cv.wait(lk)
会隐式释放
block
上的锁,因此现在另一个线程可以在
倒计时()中获得
block
上的锁。只要线程在
countDown()
中持有
block
上的锁(即使在调用
cv.notify\u all()
之后,
wait
线程也不能从
cv.wait()
返回。
wait
线程在从
cv.wait()

更新

虽然
,但我在查看您的代码时确实犯了一个新手错误

cv.wait(lk)
可能会错误返回。也就是说,它可能会返回,即使它尚未得到通知。为了防止这种情况,您应该将
wait
置于while循环下,而不是if:

void await()
{
    std::unique_lock<std::mutex> lk(block);
    while (count > 0)
        cv.wait(lk);
}
void wait()
{
std::唯一锁lk(块);
而(计数>0)
cv.等待(lk);
}

现在,如果等待错误地返回,它将重新检查条件,如果仍然不满足,则再次等待。

亲爱的上帝,这是一个错误。有人入侵了Howard的StackOverflow帐户,天哪,是个错误。有人侵入了Howard的StackOverflow帐户。