✍个人博客:Pandaconda-CSDN博客
📣专栏地址:http://t.csdnimg.cn/fYaBd
📚专栏简介:在这个专栏中,我将会分享 C++ 面试中常见的面试题给大家~
❤️如果有收获的话,欢迎点赞👍收藏📁,您的支持就是我创作的最大动力💪
25. 线程间同步通信 - 生产者消费者模型
两者生产一个就消费一个,结束后互相通知对方。
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue> //STL所有容器都不是线程安全
using namespace std;
std::mutex mtx; //定义互斥锁, 线程间互斥
std::condition_variable cv; //定义条件变量, 线程间通信
class Queue
{
public:
void put(int val)
{
//lock_guard<std::mutex>guard(mtx);//error scoped_ptr 左值拷贝构造和赋值都delete了
unique_lock<std::mutex> lck(mtx); //防止这把锁被释放了
while (!que.empty())
{
cv.wait(lck); //线程进入等待, 并把mtx锁释放
}
que.push(val);
cv.notify_all(); //其他线程得到该通知,从等待变为阻塞,获取锁后继续执行
cout << "生产者 生产:" << val << " 号物品" << endl;
}
int get()
{
//lock_guard<std::mutex>guard(mtx);
unique_lock<std::mutex>lck(mtx);
while (que.empty())
{
cv.wait(lck);
}
int val = que.front();
que.pop();
cv.notify_all();
cout << "消费者 消费:" << val << "号物品" << endl;
return val;
}
private:
queue<int> que;
};
void producer(Queue* que)
{
for (int i = 0; i < 10; i++)
{
que->put(i);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
void consumer(Queue* que)
{
for (int i = 0; i < 10; i++)
{
que->get();
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
int main()
{
Queue que;
std::thread t1(producer, &que);
std::thread t2(consumer, &que);
t1.join();
t2.join();
return 0;
}
26. 再谈 lock_guard 和 unique_lock
lock_guard 和 unique_lock
- unique_lock:不仅可以使用在简单的临界区代码段的互斥操作中,还能用在函数调用过程中。
- lock_guard:不可能用在函数参数传递或者返回过程中,只能用在简单的临界区代码段的互斥操作中。
condition_variable wait 和 notify_all 方法 - notify_all:通知在 cv 上等待的线程,条件成立了,起来干活。其它 cv 上等待的线程收到通知,从等待态到阻塞态。
27. 基于 CAS 操作的 atomic 原子类型
互斥锁比较重,效率比较低,临界区代码做的事情稍稍复杂时再用。
用 CAS 来保证 ++ – 操作的原子特性就足够了(无锁操作)。
无锁队列:
#include <iostream>
#include <mutex>
#include <condition_variable>
#include <atomic> //包含了很多原子类型
#include <list>
using namespace std;
//volatile 防止多线程对共享变量进行缓存
volatile std::atomic_bool isReady = true;
volatile std::atomic_int ccount = 0;
//int ccount = 0;
void task()
{
while (!isReady)
{
std::this_thread::yield(); //线程出让当前的cpu时间片,等待下一次调度
}
for (int i = 0; i < 1000; i++)
ccount++;
}
int main()
{
list<std::thread> tlist;
for (int i = 0; i < 10; i++) {
tlist.push_back(std::thread(task));
}
for (auto& t : tlist)
{
t.join();
}
cout << ccount << endl;
return 0;
}