尝试:
在多个线程上执行延迟启动。
问题:
我已经创建了下面的示例来证明这个想法,并尝试在x上创建一个种族代码,以证明所有线程都会同时运行。
似乎事物是序列化而不是并行运行 - 期望的行为,但也许每个线程运行的时间太短并且在另一个onse得到服务之前完成
有时一个线程会卡在cv.wait上---我在GDB中看过这个并且可以看到其中一个线程只是在第0帧中等待 - 这意味着notify_all没有唤醒所有的线程---(这是零星的行为,每次尝试运行二进制文件都会发生)
问:
使用条件变量是一个有效的方法来执行一组线程的延迟启动,这些线程具有所有并行运行的行为吗?
为什么notify_all()没有唤醒所有线程?
码
// main.cpp
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <atomic>
#include <iostream>
#include <unistd.h>
int main()
{
std::condition_variable cv;
std::mutex cv_m;
int x = 0;
std::thread t1 = std::thread([&]{std::unique_lock<std::mutex> lk(cv_m); cv.wait(lk); std::cout << "t1 x:" << x++ << std::endl;});
std::thread t2 = std::thread([&]{std::unique_lock<std::mutex> lk(cv_m); cv.wait(lk); std::cout << "t2 x:" << x++ << std::endl;});
std::thread t3 = std::thread([&]{std::unique_lock<std::mutex> lk(cv_m); cv.wait(lk); std::cout << "t3 x:" << x++ << std::endl;});
std::thread t4 = std::thread([&]{std::unique_lock<std::mutex> lk(cv_m); cv.wait(lk); std::cout << "t4 x:" << x++ << std::endl;});
std::thread t5 = std::thread([&]{std::unique_lock<std::mutex> lk(cv_m); cv.wait(lk); std::cout << "t5 x:" << x++ << std::endl;});
std::cout << "STARTING" << std::endl;
cv.notify_all();
t1.join();
t2.join();
t3.join();
t4.join();
t5.join();
std::cout << "DONE" << std::endl;
return 0;
}
编译:
g++ -std=c++14 main.cpp -lpthread
运行:
./a.out
答案 0 :(得分:3)
条件变量是无状态的。如果没有服务员,通知会丢失;可以提供spurios通知。您需要等待更改共享状态,而不是来自条件变量的信号。
当通知条件变量,超时到期或发生虚假唤醒时,线程被唤醒,并且原子重新获取互斥锁。然后线程应该检查条件并在唤醒是假的时候继续等待。
此外,在通知条件变量时,如果需要保留服务器FIFO顺序,则必须保持互斥锁。
修正:
int main()
{
std::condition_variable cv;
std::mutex cv_m;
int x = 0;
bool start = false;
auto thread_fn = [&]{
std::unique_lock<std::mutex> lk(cv_m);
while(!start)
cv.wait(lk);
std::cout << "t1 x:" << x++ << std::endl;
};
std::thread t1 = std::thread(thread_fn);
std::thread t2 = std::thread(thread_fn);
std::thread t3 = std::thread(thread_fn);
std::thread t4 = std::thread(thread_fn);
std::thread t5 = std::thread(thread_fn);
std::cout << "STARTING" << std::endl;
{
std::unique_lock<std::mutex> lock(cv_m);
start = true;
cv.notify_all();
}
t1.join();
t2.join();
t3.join();
t4.join();
t5.join();
std::cout << "DONE" << std::endl;
}