【題目1】
子線程循環 10 次,接着主線程循環 100 次,接着又回到子線程循環 10 次,接着再回到主線程又循環 100 次,如此循環50次,試寫出代碼
【題解】
首先我們來分析一下這道題...(是個剛入門的小白,分析的不好請見諒)
1、由於子線程需要循環10次不受主線程干擾,而主線程需要循環100次不受子線程干擾,所以顯然,在他們進入循環的時候需要一個鎖把這段循環鎖住,不然會導致資源被搶占(此處的資源可以理解為是循環里的cout)。(其實簡單來說互斥量是為了保證子線程和主線程的for不同時進行)
2、然后問題來了,怎么控制子線程循環后主線程循環,然后一直這樣依次循環呢?條件變量就可以做到這點,我們可以通過改變某個全局變量的值,第一次將該全局變量置為10,也就是說我們只要控制如果傳入的參數和該全局變量不等,就讓他一直等待,當執行完子線程的循環后改變這個全局變量為100,那么對於子線程來說全局變量和傳入的參數就不相等了,那么條件變量就會一直等待。當然如果一直讓他等待肯定是不對的,所以當一個線程執行完循環之后需要喚醒這個條件變量,告訴線程變量已經改變又可以開始搶資源啦。(其實條件變量就是為了控制子主線程運行的先后條件)
【代碼】

#include<thread> #include<iostream> #include<cstdio> #include<mutex> #include<condition_variable> using namespace std; int flag = 10; mutex mu; condition_variable cv; void fun(int x, char c) { for (int i = 0; i < 50; i++) { unique_lock<mutex> lock(mu); while(flag != x) cv.wait(lock);//在該線程阻塞之前會執行lock.unlock,這樣別的線程才不會被鎖住 for (int j = 0; j < x; j++) cout << c << ":" << j << endl; flag = (x == 10)? 100 : 10; cv.notify_one(); } } int main() { thread t1(fun, 10, 'A'); fun(100, 'B'); t1.join(); }
【總結】
理解這段代碼的時候,被wait()弄了好久,可能是我太蠢qwq那么來說一下wait()吧,我們分兩種情況來說。
(1)一開始,主線程先搶到了鎖
那么就會判斷flag是否等於x,很顯然如果是主線程先拿到鎖此時flag=10,x=100不等,那么這個時候主線程就會執行wait(),也就是會被阻塞,然后因為wait()自身有這樣一個機制(當他執行的時候會自動釋放鎖嗎,也就是會自動執行unlock,給其他線程一個拿鎖的機會),這個時候子線程就會拿到鎖,並且判斷fag是否等於x,這時候明顯是相等的,那么就會進行下面的一系列循環,這個時候重點來了,一定要改變全局變量!!如果不改變會是什么結果呢?假設我們把那句話注釋掉直接執行notify_one(),那么主線程就會被喚醒它的wait()又會自動參與搶鎖,由於flag沒有改變,那么flag和x的值還是相等,所以它依然會被阻塞,那么依舊就是子線程執行,就不滿足題意了。
(2)一開始,子線程先搶到了鎖
因為滿足flag=x,那么會執行接下來的for,按部就班改個flag,然后喚醒被wait的線程(這時候其實沒有),因為執行完一個循環,uniqie_lock會自動釋放鎖,然后子線程和主線程就又開始搶鎖了,這次我們假設還是子線程先搶到了鎖,但由於修改了flag,此時flag!=x,子線程就被阻塞,然后就和情況(1)差不多啦。
【題目2】
編寫一個程序,開啟3個線程,這3個線程的ID分別為A、B、C,每個線程將自己的ID在屏幕上打印10遍,要求輸出結果必須按ABC的順序顯示;如:ABCABC….依次遞推。
【題解】
其實只要理解了上一題,就是一個套路啦。這里有所不同的是有3個線程,所以最后喚醒條件變量的時候記得用notify_all()。
【代碼】

#include<thread> #include<iostream> #include<cstdio> #include<mutex> #include<condition_variable> using namespace std; int flag = 0; mutex mu; condition_variable cv; void fun(int x) { for (int i = 0; i < 10; i++) { unique_lock<mutex>lock(mu); while (x != flag) cv.wait(lock); cout << static_cast<char>('A' + x) << " "; flag = (flag + 1) % 3; cv.notify_all(); } } int main() { thread t1(fun, 1); thread t2(fun, 2); fun(0); t1.join(); t2.join(); }