生产者 - 消费者模型
重点知识
unique_lock 的作用
unique_lock
是 C++ 标准库 mutex
的 RAII(资源获取即初始化)封装,用于自动管理互斥锁。当执行 unique_lock<mutex> lock(_mutex);
时:
- 当前线程尝试获取
mutex
锁(如果其他线程已经持有锁,则当前线程会阻塞等待,直到锁被释放)。 - 一旦成功获取锁,在
lock
对象的生命周期内,当前线程独占访问受保护的资源。 - 当
lock
对象销毁时(如作用域结束),mutex
会自动解锁,从而可以避免死锁或资源泄露。
unique_lock 与 lock_guard 的区别
unique_lock
- 使用语法(
unique_lock<mutex> lock(_mutex);
) - 可以手动解锁(
lock.unlock()
)。 - 可以延迟加锁(
unique_lock<mutex> lock(_mutex, defer_lock);
)。 - 可以移动赋值(
unique_lock
可被转移,但 lock_guard
不能)。 - 通常与
condition_variable
搭配使用,因为 condition_variable::wait()
函数需要传入 unique_lock
参数(不能使用 lock_guard
)。
lock_guard
- 使用语法(
lock_guard<mutex> lock(_mutex);
) - 作用域结束时自动解锁,不可以手动解锁。
- 比
unique_lock
更轻量级,性能更好(因为没有 unlock ()
之类的额外操作)。
总结
- 如果只需要简单加锁 / 解锁,建议使用
lock_guard
,效率更高。 - 如果需要手动控制解锁,建议使用
unique_lock
。
案例代码
模拟实现生产者线程生产一条数据,消费者线程就消费一条数据,两个线程一直交替执行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
| #include <iostream> #include <queue> #include <thread> #include <mutex> #include <chrono> #include <atomic> #include <condition_variable>
using namespace std;
mutex _mutex; queue<int> _queue; condition_variable _cv; atomic_bool _finish(false);
void produce() { while (!_finish) { unique_lock<mutex> lock(_mutex);
_cv.wait(lock, [] { return _queue.empty(); });
this_thread::sleep_for(chrono::milliseconds(500));
int item = rand() % 1000 + 1; _queue.push(item); cout << "生产: " << item << endl;
_cv.notify_all(); } }
void consume() { while (!_finish) { unique_lock<mutex> lock(_mutex);
_cv.wait(lock, [] { return !_queue.empty(); });
this_thread::sleep_for(chrono::milliseconds(500));
int item = _queue.front(); _queue.pop(); cout << "消费: " << item << endl;
_cv.notify_all(); } }
int main() { srand(time(nullptr));
thread producer(produce); thread consumer(consume);
this_thread::sleep_for(chrono::seconds(60));
_finish = true;
_cv.notify_all();
producer.join(); consumer.join();
return 0; }
|
程序运行的输出结果如下:
1 2 3 4 5 6 7 8 9 10 11
| 生产: 98 消费: 98 生产: 635 消费: 635 生产: 318 消费: 318 生产: 513 消费: 513 生产: 413 消费: 413 ......
|