同步并发操作

考虑一种常见情景:一个线程需要等待另一个线程完成任务才能够完成其自己的任务,该怎么办呢?有三种方案:

第一个方案:不断检查由互斥元保护的共享数据中的标识;

第二个方案:调用函数std::this_thread::sleep_for()在检查之间休眠一会儿;

第三个方案:条件变量;

 

条件变量

1. 当某个线程(准备数据的线程,用的是std::lock_guard)已经确定条件得到满足,它就可以通知notify_one()一个或多个正在条件变量上进行等待wait()(解锁互斥元,阻塞线程)的线程(处理数据的线程,用的是std::unique_lock而非std::lock_guard,因为等待中的线程在等待期间必须解锁互斥元并在这之后重新将其锁定),以便唤醒它们并让它们继续处理。

2. 需要和互斥元一起工作,比如std::condition_varibale与std::mutex合作。

 

下面举个栗子:

 

 1 #include <iostream>
 2 #include <string>
 3 #include <thread>
 4 #include <mutex>
 5 #include <condition_variable>
 6 
 7 std::mutex m;
 8 std::condition_variable cv;
 9 std::string data;
10 bool ready = false;
11 bool processed = false;
12 
13 void worker_thread()
14 {
15     // Wait until main() sends data
16     std::unique_lock<std::mutex> lk(m);
17     ///检查条件,满足时返回,不满足时解锁互斥元并阻塞线程
18     cv.wait(lk, []{return ready; });
19 
20     // after the wait, we own the lock.
21     std::cout << "Worker thread is processing data\n";
22     data += " after processing";
23 
24     // Send data back to main()
25     processed = true;
26     std::cout << "Worker thread signals data processing completed\n";
27 
28     // Manual unlocking is done before notifying, to avoid waking up
29     // the waiting thread only to block again (see notify_one for details)
30     lk.unlock();
31     cv.notify_one();
32 }
33 
34 int main()
35 {
36     std::thread worker(worker_thread);
37 
38     data = "Example data";
39     // send data to the worker thread
40     {
41         std::lock_guard<std::mutex> lk(m);
42         ready = true;
43         std::cout << "main() signals data ready for processing\n";
44     }
45     cv.notify_one();
46 
47     // wait for the worker
48     {
49         std::unique_lock<std::mutex> lk(m);
50         ///检查条件,满足时返回,不满足时解锁互斥元并阻塞线程
51         cv.wait(lk, []{return processed; }); 
52     }
53     std::cout << "Back in main(), data = " << data << '\n';
54 
55     ///确保在std::thread对象被销毁前已调用join()(即等待线程完成)或者detach()(即在后台运行)
56     ///detach一般在线程启动后就可以调用了,而join调用的位置要考虑好
57     ///如果此处不等待线程完成,那么main线程结束后,新建的线程可能仍在运行
58     worker.join();
59 }

 

运行结果如下:

posted @ 2018-01-12 14:46  SAPCE  阅读(309)  评论(0编辑  收藏  举报