线程同步是一个经常出现的场景,考虑一个生产者消费者模式,一个线程作为生产,一个线程作为消费。生产者往一个队列中加入元素,消费者往一个队列中取元素。实现对一个公共区域的同时访问操作,是C++多线程经常会遇到的问题,所以C++提供了线程同步的机制。
1.消费者轮询。
参考下面代码:一个线程运行Producer,一个线程运行Comsumer,共同操作一个队列,这会导致严重问题:CPU会被跑满、一个线程加任务,一个线程取任务,导致共享资源被同时访问。当任务较少时,消费者循环访问队列,CPU被无效使用。这种方式好比你无时无刻都要去检查你钱包里的钱有没有多出来,有的话就用了它,这样你估计会累死。
std::queue<Element> que;
void Producer()
{
while (true) //循环放数据
{
que.push(Element());
}
}
void Comsumer()
{
while (true) //有数据,取数据
{
if (!que.empty())
que.pop();
}
}
int main()
{
std::thread thProducer(Producer);
std::thread thComsumer(Comsumer);
//......省略以下代码
return 0;
}
解决CPU被无效使用的情况,我们可以用线程短暂休眠。则就是第二种方式。
2.消费者轮询加延迟。
将消费者和生产者都加上延迟,这样当没有任务时,消费者休眠,生产者投放,节约了CPU。这种情况就是,你每隔2小时检查你的钱包里的钱,有就花了,没有就再休息。在任务量小时,出现问题的概率少,在任务量大时,会严重出现共享资源同时访问的问题----生产者消费者同时操作公共队列。
不恰当的例子就是:两个人分别往钱包里放钱和取钱,OK,结果把钱包撤破了,扯破了之后谁都用不了了。所有我们希望消费者和生成者任一时刻,只有一个人在访问公共的队列。
void Comsumer()
{
while (true) //有数据,取数据
{
if (!que.empty())
que.pop();
if (que.empty())
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
引出我们的第三种方式,互斥量 。
3.使用std::mutex。锁的特点是:当获取锁操作失