熱線電話:0755-23712116
郵箱:contact@shuangyi-tech.com
地址:深圳市寶安區(qū)沙井街道后亭茅洲山工業(yè)園工業(yè)大廈全至科技創(chuàng)新園科創(chuàng)大廈2層2A
當某個線程持有這把鎖的時候(就是所謂的加鎖),那么這個線程是獨占所有的資源,這里的資源指的是執(zhí)行的權限,其他要搶奪資源的線程都不得不等待。在很多情況下,這都容易適用,但是有些情況下,卻會產(chǎn)生一些異常情況。
在生產(chǎn)消費者模型當中,肯定都會用到互斥鎖的機制的,當生產(chǎn)者往隊列中放數(shù)據(jù)的瞬間,消費者是不能取數(shù)據(jù)的,那這時候可能會碰見一個問題,如果生成者因為某些原因,放數(shù)據(jù)過慢,但是消費者取數(shù)據(jù)很快,當隊列中沒有數(shù)據(jù)了,消費者還去取的話,就會發(fā)生異常情況。有些人可能會說,加個條件判斷一下隊列是否為空不就可以了。
這個肯定是當然可以的,但是在隊列依舊沒有數(shù)據(jù)的這一段時間,是要不斷的循環(huán)判斷這個條件,CPU肯定是會飆升的,浪費了很多不必要的資源。
這時候我們設想,能否設計這樣的一種機制,如果在隊列沒有數(shù)據(jù)的時候,消費者線程能一直阻塞在那里,等待著別人給它喚醒,在生產(chǎn)者往隊列中放入數(shù)據(jù)的時候通知一下這個等待線程,喚醒它,告訴它可以來取數(shù)據(jù)了。
于是多線程中的條件變量就橫空出世!
條件變量是多線程數(shù)據(jù)同步的一種操作,不管是用哪種框架,哪種語言實現(xiàn)多線程的功能,條件變量都是不得不考慮的一種情況。C++中提供了#include <condition_variable>頭文件,里面就包含了條件變量的相關類。其中有兩個非常重要的接口,wait()和notify_one(),wait()可以讓線程陷入休眠狀態(tài),意思就是不干活了,notify_one()就是喚醒真正休眠狀態(tài)的線程,開始干活了。當然還有notify_all()這個接口,顧名思義,就是通知所有正在等待的線程,起來干活了。
以下是代碼的實現(xiàn)部分
#include <iostream>
#include <deque>
#include <thread>
#include <mutex>
#include <condition_variable>
using namespace std;
deque<int> q;
mutex mt;
condition_variable cond;
void thread_producer()
{
int count = 10;
while (count > 0)
{
unique_lock<mutex> unique(mt);
q.push_front(count);
unique.unlock();
cout << "producer a value: " << count << endl;
cond.notify_one();
this_thread::sleep_for(chrono::seconds(1));
count--;
}
}
void thread_consumer()
{
int data = 0;
while (data != 1)
{
unique_lock<mutex> unique(mt);
while (q.empty())
cond.wait(unique);
data = q.back();
q.pop_back();
cout << "consumer a value: " << data << endl;
unique.unlock();
}
}
int main()
{
thread t1(thread_consumer);
thread t2(thread_producer);
t1.join();
t2.join();
return 0;
}
生產(chǎn)者:首先生產(chǎn)者利用unique_lock來加鎖,然后將生產(chǎn)的數(shù)據(jù)放入隊列,打印,解鎖,一旦解鎖之后,消費者獲得了執(zhí)行機會。
消費者:另一方面消費者就會通過unique_lock獲得控制權,也就是獲得鎖,然后判斷隊列為空的話就一直盜用wait()函數(shù)阻塞在那里,等待其他線程來喚醒它。而阻塞該線程時,該函數(shù)會自動解鎖,允許其他線程執(zhí)行。
生產(chǎn)者:再次回到生產(chǎn)者這里,生產(chǎn)者線程利用利用條件變量cond.notify_one()來通知阻塞的線程起來干活了。
消費者:阻塞在那里的消費者線程一旦得到notify喚醒,該函數(shù)取消阻塞并獲取鎖,然后取出隊列中的數(shù)據(jù),并打印,最后解鎖。
生產(chǎn)者:再次回到生產(chǎn)者,然后生產(chǎn)者休眠1秒,這里休眠是為了模擬生產(chǎn)者生產(chǎn)慢的情況,實際開發(fā)的時候不要去休眠。最后減一,進入下一次生產(chǎn)。
以上就是利用條件變量來實現(xiàn)生產(chǎn)消費者模型,這個會大大降低CPU的占有率,當然代價就是編程稍微有點麻煩,但與這優(yōu)化程序來比,這肯定是值的。