nnu*_*ols 1 c++ multithreading race-condition
考虑第一个线程函数和全局变量:
std::mutex mut;
std::condition_variable officer;
bool firstPlayerIsReady = false;
bool secondPlayerIsReady = false;
Run Code Online (Sandbox Code Playgroud)
void firstPlayer(){
constexpr auto doIt = true;
while(doIt)
{
std::unique_lock lock{mut};
auto toContinue = ring();
secondPlayerIsReady = true;
firstPlayerIsReady = false;
officer.notify_one(); //#1
if(!toContinue) return;
officer.wait(lock,[=](){ return firstPlayerIsReady;});
}
}
Run Code Online (Sandbox Code Playgroud)
它调用一些ring和ring()返回一个连续条件; 然后它会在下一个循环中更新每个线程的准备值;
考虑下一个线程:
void secondPlayer(){
constexpr auto doIt = true;
while(doIt)
{
auto period = std::chrono::seconds(5);
std::this_thread::sleep_for(period);
std::unique_lock lock{mut}; //#2
officer.wait(lock,[this](){ return secondPlayerIsReady;});
auto toContinue = ring();
firstPlayerIsReady = true;
secondPlayerIsReady = false;
officer.notify_one();
if(!toContinue) return;
}
}
Run Code Online (Sandbox Code Playgroud)
这个线程等待5秒后用wait()锁定,直到第一个线程调用notify_one(); 此外,类似于第一个线程.
先验,#1标记的行比#2标记的行更早执行,因此通知的发送时间早于第二个线程被锁定.问题是 - 是否有notify_one()队列?否则,显然没有发送通知.
没有队列.如果一个线程调用notify_one并且没有其他线程在等待它将不会执行任何操作.
这就是你的例子中你有谓词的原因
officer.wait(lock,[this](){ return secondPlayerIsReady;});
Run Code Online (Sandbox Code Playgroud)
因此,当一个线程调用它时,如果secondPlayerIsReady为true,那么该线程将不会等待,而只是跳过这一行.
因此notify_one,只要正确设置了标志,"早期" 调用就不是问题.请记住,修改后,该标志需要由互斥锁保护.