lock_guard vs unique_guard
lock_guard: 提供了一种RAII机制,在一个scope块中拥有一个mutex。当创建一个lock_guard对象的时候,它将会尝试拥有mutex,当离开lock_guard对象创建的scope的时候,lock_guard对象被析构并且释放mutex。lock_guard是不可拷贝的。
unique_lock: unique_lock是一个通用的mutex封装器,通常与条件变量一起使用,能够手动lock()
和unlock()
(提供了相关API)。支持移动语义,但不可拷贝。
参考文章
condition_variable
condition_variable:是一个同步元语,与mutex一起使用可以阻塞一个或多个线程,直到有一个线程修改了一个共享变量(条件)并通知其他条件变量。
线程如果想要修改共享变量(条件),必须满足以下条件:
- 获取到mutex(一般是通过lock_guard)
- 当持有锁的时候修改共享变量
- 通过条件变量调用notify_one或notify_all(能够在释放锁之后再调用)
即使共享变量是原子的,也必须要再拥有锁的时候修改,才能正确的通知到正在等待的线程。任何想要在条件变量上等待的线程,必须满足以下条件:
-
使用
unique_lock<mutex>
来保护共享变量 -
做下面的事情之一:
- 检查条件,以防它已经更新并通知
- 在条件变量上调用wait, wait_for或者wait_until(原子的释放mutex并挂起线程,直到条件变量被通知、时间过期或假唤醒(spurious wakeup),然后在返回前自动获取mutex)
- 检查条件,如果条件不满足继续等待
或
- 使用自己重载的wait, wait_for和wait_until,要执行2.2中相同的三个步骤。
条件变量只和unique_lock<mutex>
一起工作。
#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <unistd.h>
using namespace std;
mutex m;
condition_variable cv;
string data;
bool ready = false;
bool processed = false;
void worker_thread() {
unique_lock<mutex> lk(m);
cv.wait(lk, []{return ready;});
// 如果使用wait_for,则等待一段时间或者条件满足之后就会继续执行
// cv.wait_for(lk, chrono::seconds(5), []{return ready;});
cout << "worker thread is processing data" << endl;
data += " after processing";
processed = true;
cout << "worker thread signals data processing completed" << endl;
lk.unlock();
cv.notify_one();
}
int main() {
thread worker(worker_thread);
data = "Example data";
sleep(20);
{
lock_guard<mutex> lk(m);
ready = true;
cout << "main() signals data ready for processing" << endl;
}
cv.notify_one();
{
unique_lock<mutex> lk(m);
cv.wait(lk, []{return processed;});
cout << "Back in main(), data=" << data << endl;
}
worker.join();
}
编译及其输出结果:
$ g++ -o test_condition_variable test_condition_variable.cpp -lpthread
# 使用wait()
$ ./test_condition_variable
main() signals data ready for processing
worker thread is processing data # 等到主线程将条件设置为true子线程才继续执行
worker thread signals data processing completed
Back in main(), data=Example data after processing
# 使用wait_for(),时间到期或条件满足,这次测试的是时间到期
$ ./test_condition_variable
worker thread is processing data # 子线程等到5秒后,即使条件没有满足也继续执行了
worker thread signals data processing completed
main() signals data ready for processing
Back in main(), data=Example data after processing