這篇文章主要介紹了C++11中線程鎖和條件變量怎么應(yīng)用的相關(guān)知識(shí),內(nèi)容詳細(xì)易懂,操作簡單快捷,具有一定借鑒價(jià)值,相信大家閱讀完這篇C++11中線程鎖和條件變量怎么應(yīng)用文章都會(huì)有所收獲,下面我們一起來看看吧。
創(chuàng)新互聯(lián)建站長期為成百上千家客戶提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊(duì)從業(yè)經(jīng)驗(yàn)10年,關(guān)注不同地域、不同群體,并針對(duì)不同對(duì)象提供差異化的產(chǎn)品和服務(wù);打造開放共贏平臺(tái),與合作伙伴共同營造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為大峪企業(yè)提供專業(yè)的網(wǎng)站設(shè)計(jì)、成都網(wǎng)站制作,大峪網(wǎng)站改版等技術(shù)服務(wù)。擁有十余年豐富建站經(jīng)驗(yàn)和眾多成功案例,為您定制開發(fā)。std::thread類, 位于<thread>頭文件,實(shí)現(xiàn)了線程操作。std::thread可以和普通函數(shù)和 lambda 表達(dá)式搭配使用。它還允許向線程的執(zhí)行函數(shù)傳遞任意多參數(shù)。
#include <thread> void func() { // do some work } int main() { std::thread t(func); t.join(); return 0; }
上面的例子中,t是一個(gè)線程實(shí)例,函數(shù)func()在該線程運(yùn)行。調(diào)用join()函數(shù)是為了阻塞當(dāng)前線程(此處即主線程),直到t線程執(zhí)行完畢。線程函數(shù)的返回值都會(huì)被忽略,但線程函數(shù)接受任意數(shù)目的輸入?yún)?shù)。
void func(int i, double d, const std::string& s) { std::cout << i << ", " << d << ", " << s << std::endl; } int main() { std::thread t(func, 1, 12.50, "sample"); t.join(); return 0; }
雖然可以向線程函數(shù)傳遞任意多參數(shù),但都必須以值傳遞。如果需以引用傳遞,則必須以std::ref或std::cref封裝,如下例所示:
void func(int& a) { a++; } int main() { int a = 42; std::thread t(func, std::ref(a)); t.join(); std::stringcout << a << std::endl; return 0; }
這個(gè)程序會(huì)打印43,但如果不用std::ref封裝,則輸出會(huì)是42。
除了join函數(shù),這個(gè)類還提供更多的操作:
swap:交換兩個(gè)線程實(shí)例的句柄
detach:允許一個(gè)線程繼續(xù)獨(dú)立于線程實(shí)例運(yùn)行;detach 過的線程不可以再 join
int main() { std::thread t(funct); t.detach(); return 0; }
一個(gè)重要的知識(shí)點(diǎn)是,如果一個(gè)線程函數(shù)拋出異常,并不會(huì)被常規(guī)的try-catch方法捕獲。也就是說,下面的寫法是不會(huì)奏效的:
try { std::thread t1(func); std::thread t2(func); t1.join(); t2.join(); } catch(const std::exception& ex) { std::cout << ex.what() << std::endl; }
要追蹤線程間的異常,你可以在線程函數(shù)內(nèi)捕獲,暫時(shí)存儲(chǔ)在一個(gè)稍后可以訪問的結(jié)構(gòu)內(nèi)。
std::mutex g_mutex; std::vector<std::exception_ptr> g_exceptions; void throw_function() { throw std::exception("something wrong happened"); } void func() { try { throw_function(); } catch(...) { std::lock_guard<std::mutex> lock(g_mutex); g_exceptions.push_back(std::current_exception()); } } int main() { g_exceptions.clear(); std::thread t(func); t.join(); for(auto& e : g_exceptions) { try { if(e != nullptr) { std::rethrow_exception(e); } } catch(const std::exception& e) { std::cout << e.what() << std::endl; } } return 0; }
關(guān)于捕獲和處理異常,更深入的信息可以參看Handling C++ exceptions thrown from worker thread in the main thread和How can I propagate exceptions between threads?。
此外,值得注意的是,頭文件還在 `std::this_thread` 命名空間下提供了一些輔助函數(shù):
get_id: 返回當(dāng)前線程的 id
yield: 告知調(diào)度器運(yùn)行其他線程,可用于當(dāng)前處于繁忙的等待狀態(tài)
sleep_for:給定時(shí)長,阻塞當(dāng)前線程
sleep_until:阻塞當(dāng)前線程至給定時(shí)間點(diǎn)
在上個(gè)例子中,我們需要對(duì)g_exceptions這個(gè) vector 的訪問進(jìn)行同步處理,確保同一時(shí)刻只有一個(gè)線程能向它插入新的元素。為此我使用了一個(gè) mutex 和一個(gè)鎖(lock)。mutex 是同步操作的主體,在 C++ 11 的<mutex>頭文件中,有四種風(fēng)格的實(shí)現(xiàn):
mutex:提供了核心的lock()unlock()方法,以及當(dāng) mutex 不可用時(shí)就會(huì)返回的非阻塞方法try_lock()
recursive_mutex:允許同一線程內(nèi)對(duì)同一 mutex 的多重持有
timed_mutex: 與mutex類似,但多了try_lock_for()try_lock_until()兩個(gè)方法,用于在特定時(shí)長里持有 mutex,或持有 mutex 直到某個(gè)特定時(shí)間點(diǎn)
recursive_timed_mutex:recursive_mutex和timed_mutex的結(jié)合
下面是一個(gè)使用std::mutex的例子(注意get_id()和sleep_for()兩個(gè)輔助方法的使用)。
#include <iostream> #include <thread> #include <mutex> #include <chrono> std::mutex g_lock; void func() { g_lock.lock(); std::cout << "entered thread " << std::this_thread::get_id() << std::endl; std::this_thread::sleep_for(std::chrono::seconds(rand() % 10)); std::cout << "leaving thread " << std::this_thread::get_id() << std::endl; g_lock.unlock(); } int main() { srand((unsigned int)time(0)); std::thread t1(func); std::thread t2(func); std::thread t3(func); t1.join(); t2.join(); t3.join(); return 0; }
輸出如下:
entered thread 10144
leaving thread 10144
entered thread 4188
leaving thread 4188
entered thread 3424
leaving thread 3424
lock()unlock()兩個(gè)方法應(yīng)該很好懂,前者鎖住 mutex,如果該 mutex 不可用,則阻塞線程;稍后,后者解鎖線程。
下面一個(gè)例子展示了一個(gè)簡單的線程安全的容器(內(nèi)部使用了std::vector)。該容器提供用于添加單一元素的add()方法,以及添加多個(gè)元素的addrange()方法(內(nèi)部調(diào)用add()實(shí)現(xiàn))。
注意:盡管如此,下面會(huì)指出,由于va_args的使用等原因,這個(gè)容器并非真正線程安全。此外,dump()方法不應(yīng)屬于容器,在實(shí)際實(shí)現(xiàn)中它應(yīng)該作為一個(gè)獨(dú)立的輔助函數(shù)。這個(gè)例子的目的僅僅是展示 mutex 的相關(guān)概念,而非實(shí)現(xiàn)一個(gè)完整的線程安全的容器。
template <typename T> class container { std::mutex _lock; std::vector<T> _elements; public: void add(T element) { _lock.lock(); _elements.push_back(element); _lock.unlock(); } void addrange(int num, ...) { va_list arguments; va_start(arguments, num); for (int i = 0; i < num; i++) { _lock.lock(); add(va_arg(arguments, T)); _lock.unlock(); } va_end(arguments); } void dump() { _lock.lock(); for(auto e : _elements) std::cout << e << std::endl; _lock.unlock(); } }; void func(container<int>& cont) { cont.addrange(3, rand(), rand(), rand()); } int main() { srand((unsigned int)time(0)); container<int> cont; std::thread t1(func, std::ref(cont)); std::thread t2(func, std::ref(cont)); std::thread t3(func, std::ref(cont)); t1.join(); t2.join(); t3.join(); cont.dump(); return 0; }
當(dāng)你運(yùn)行這個(gè)程序時(shí),會(huì)進(jìn)入死鎖。原因:在 mutex 被釋放前,容器嘗試多次持有它,這顯然不可能。這就是為什么引入std::recursive_mutex,它允許一個(gè)線程對(duì) mutex 多重持有。允許的較大持有次數(shù)并不確定,但當(dāng)達(dá)到上限時(shí),線程鎖會(huì)拋出std::system_error錯(cuò)誤。因此,要解決上面例子的錯(cuò)誤,除了修改addrange令其不再調(diào)用lock和unlock之外,可以用std::recursive_mutex代替mutex。
template <typename T> class container { std::recursive_mutex _lock; // ... };
成功輸出:
6334
18467
41
6334
18467
41
6334
18467
41
敏銳的讀者可能注意到,每次調(diào)用func()輸出的都是相同的數(shù)字。這是因?yàn)椋瑂eed 是線程局部量,調(diào)用srand()只會(huì)在主線程中初始化 seed,在其他工作線程中 seed 并未被初始化,所以每次得到的數(shù)字都是一樣的。
手動(dòng)加鎖和解鎖可能造成問題,比如忘記解鎖或鎖的次序出錯(cuò),都會(huì)造成死鎖。C++ 11 標(biāo)準(zhǔn)提供了若干類和函數(shù)來解決這個(gè)問題。封裝類允許以 RAII 風(fēng)格使用 mutex,在一個(gè)鎖的生存周期內(nèi)自動(dòng)加鎖和解鎖。這些封裝類包括:
lock_guard:當(dāng)一個(gè)實(shí)例被創(chuàng)建時(shí),會(huì)嘗試持有 mutex (通過調(diào)用lock());當(dāng)實(shí)例銷毀時(shí),自動(dòng)釋放 mutex (通過調(diào)用unlock())。不允許拷貝。
unique_lock:通用 mutex 封裝類,與lock_guard不同,還支持延遲鎖、計(jì)時(shí)鎖、遞歸鎖、移交鎖的持有權(quán),以及使用條件變量。不允許拷貝,但允許轉(zhuǎn)移(move)。
借助這些封裝類,可以把容器改寫為:
template <typename T> class container { std::recursive_mutex _lock; std::vector<T> _elements; public: void add(T element) { std::lock_guard<std::recursive_mutex> locker(_lock); _elements.push_back(element); } void addrange(int num, ...) { va_list arguments; va_start(arguments, num); for (int i = 0; i < num; i++) { std::lock_guard<std::recursive_mutex> locker(_lock); add(va_arg(arguments, T)); } va_end(arguments); } void dump() { std::lock_guard<std::recursive_mutex> locker(_lock); for(auto e : _elements) std::cout << e << std::endl; } };
讀者可能會(huì)提出,dump()方法不更改容器的狀態(tài),應(yīng)該設(shè)為 const。但如果你添加 const 關(guān)鍵字,會(huì)得到如下編譯錯(cuò)誤:
‘std::lock_guard<_Mutex>::lock_guard(_Mutex &)' : cannot convert parameter 1 from ‘const std::recursive_mutex' to ‘std::recursive_mutex &'
一個(gè) mutex (不管何種風(fēng)格)必須被持有和釋放,這意味著lock()unlock方法必被調(diào)用,這兩個(gè)方法是 non-const 的。所以,邏輯上lock_guard的聲明不能是 const (若該方法 為 const,則 mutex 也為 const)。這個(gè)問題的解決辦法是,將 mutex 設(shè)為mutable。mutable允許由 const 方法更改 mutex 狀態(tài)。不過,這種用法僅限于隱式的,或「元(meta)」?fàn)顟B(tài)——譬如,運(yùn)算過的高速緩存、檢索完成的數(shù)據(jù),使得下次調(diào)用能瞬間完成;或者,改變像 mutex 之類的位元,僅僅作為一個(gè)對(duì)象的實(shí)際狀態(tài)的補(bǔ)充。
template <typename T> class container { mutable std::recursive_mutex _lock; std::vector<T> _elements; public: void dump() const { std::lock_guard<std::recursive_mutex> locker(_lock); for(auto e : _elements) std::cout << e << std::endl; } };
這些封裝類鎖的構(gòu)造函數(shù)可以通過重載的聲明來指定鎖的策略。可用的策略有:
defer_lock_t類型的defer_lock:不持有 mutex
try_to_lock_t類型的try_to_lock: 嘗試持有 mutex 而不阻塞線程
adopt_lock_t類型的adopt_lock:假定調(diào)用它的線程已持有 mutex
這些策略的聲明方式如下:
struct defer_lock_t { }; struct try_to_lock_t { }; struct adopt_lock_t { }; constexpr std::defer_lock_t defer_lock = std::defer_lock_t(); constexpr std::try_to_lock_t try_to_lock = std::try_to_lock_t(); constexpr std::adopt_lock_t adopt_lock = std::adopt_lock_t();
除了這些 mutex 封裝類之外,標(biāo)準(zhǔn)庫還提供了兩個(gè)方法用于鎖住一個(gè)或多個(gè) mutex:
lock:鎖住 mutex,通過一個(gè)避免了死鎖的算法(通過調(diào)用lock(),try_lock()和unlock()實(shí)現(xiàn))
try_lock:嘗試通過調(diào)用try_lock()來調(diào)用多個(gè) mutex,調(diào)用次序由 mutex 的指定次序而定
下面是一個(gè)死鎖案例:有一個(gè)元素容器,以及一個(gè)exchange()函數(shù)用于互換兩個(gè)容器里的某個(gè)元素。為了實(shí)現(xiàn)線程安全,這個(gè)函數(shù)通過一個(gè)和容器關(guān)聯(lián)的 mutex,對(duì)這兩個(gè)容器的訪問進(jìn)行同步。
template <typename T> class container { public: std::mutex _lock; std::set<T> _elements; void add(T element) { _elements.insert(element); } void remove(T element) { _elements.erase(element); } }; void exchange(container<int>& cont1, container<int>& cont2, int value) { cont1._lock.lock(); std::this_thread::sleep_for(std::chrono::seconds(1)); // <-- forces context switch to simulate the deadlock cont2._lock.lock(); cont1.remove(value); cont2.add(value); cont1._lock.unlock(); cont2._lock.unlock(); }
假如這個(gè)函數(shù)在兩個(gè)線程中被調(diào)用,在其中一個(gè)線程中,一個(gè)元素被移出容器 1 而加到容器 2;在另一個(gè)線程中,它被移出容器 2 而加到容器 1。這可能導(dǎo)致死鎖——當(dāng)一個(gè)線程剛持有第一個(gè)鎖,程序馬上切入另一個(gè)線程的時(shí)候。
int main() { srand((unsigned int)time(NULL)); container<int> cont1; cont1.add(1); cont1.add(2); cont1.add(3); container<int> cont2; cont2.add(4); cont2.add(5); cont2.add(6); std::thread t1(exchange, std::ref(cont1), std::ref(cont2), 3); std::thread t2(exchange, std::ref(cont2), std::ref(cont1), 6); t1.join(); t2.join(); return 0; }
要解決這個(gè)問題,可以使用std::lock,保證所有的鎖都以不會(huì)死鎖的方式被持有:
void exchange(container<int>& cont1, container<int>& cont2, int value) { std::lock(cont1._lock, cont2._lock); cont1.remove(value); cont2.add(value); cont1._lock.unlock(); cont2._lock.unlock(); }
C++ 11 提供的另一個(gè)同步機(jī)制是條件變量,用于阻塞一個(gè)或多個(gè)線程,直到接收到另一個(gè)線程的通知信號(hào),或暫停信號(hào),或偽喚醒信號(hào)。在<condition_variable>頭文件里,有兩個(gè)風(fēng)格的條件變量實(shí)現(xiàn):
condition_variable:所有需要等待這個(gè)條件變量的線程,必須先持有一個(gè)std::unique_lock
condition_variable_any:更通用的實(shí)現(xiàn),任何滿足鎖的基本條件(提供lock()和unlock()功能)的類型都可以使用;在性能和系統(tǒng)資源占用方面可能消耗更多,因而只有在它的靈活性成為必需的情況下才應(yīng)優(yōu)先使用
條件變量的工作機(jī)制如下:
至少有一個(gè)線程在等待某個(gè)條件成立。等待的線程必須先持有一個(gè)unique_lock鎖。這個(gè)鎖被傳遞給wait()方法,這會(huì)釋放 mutex,阻塞線程直至條件變量收到通知信號(hào)。當(dāng)收到通知信號(hào),線程喚醒,重新持有鎖。
至少有一個(gè)線程在發(fā)送條件成立的通知信號(hào)。信號(hào)的發(fā)送可以用notify_one()方法, 只解鎖任意一個(gè)正在等待通知信號(hào)的線程,也可以用notify_all()方法, 解鎖所有等待條件成立信號(hào)的線程。
在多核處理器系統(tǒng)上,由于使條件喚醒完全可預(yù)測的某些復(fù)雜機(jī)制的存在,可能發(fā)生偽喚醒,即一個(gè)線程在沒有別的線程發(fā)送通知信號(hào)時(shí)也會(huì)喚醒。因而,當(dāng)線程喚醒時(shí),檢查條件是否成立是必要的。而且,偽喚醒可能多次發(fā)生,所以條件檢查要在一個(gè)循環(huán)里進(jìn)行。
下面的代碼展示使用條件變量進(jìn)行線程同步的實(shí)例: 幾個(gè)工作員線程在運(yùn)行過程中會(huì)產(chǎn)生錯(cuò)誤,他們將錯(cuò)誤碼存在一個(gè)隊(duì)列里。一個(gè)記錄員線程處理這些錯(cuò)誤碼,將錯(cuò)誤碼從記錄隊(duì)列里取出并打印出來。工作員會(huì)在發(fā)生錯(cuò)誤時(shí),給記錄員發(fā)送信號(hào)。記錄員則等待條件變量的通知信號(hào)。為了避免偽喚醒,等待工作放在一個(gè)檢查布爾值的循環(huán)內(nèi)。
#include <thread> #include <mutex> #include <condition_variable> #include <iostream> #include <queue> #include <random> std::mutex g_lockprint; std::mutex g_lockqueue; std::condition_variable g_queuecheck; std::queue<int> g_codes; bool g_done; bool g_notified; void workerfunc(int id, std::mt19937& generator) { // print a starting message { std::unique_lock<std::mutex> locker(g_lockprint); std::cout << "[worker " << id << "]\trunning..." << std::endl; } // simulate work std::this_thread::sleep_for(std::chrono::seconds(1 + generator() % 5)); // simulate error int errorcode = id*100+1; { std::unique_lock<std::mutex> locker(g_lockprint); std::cout << "[worker " << id << "]\tan error occurred: " << errorcode << std::endl; } // notify error to be logged { std::unique_lock<std::mutex> locker(g_lockqueue); g_codes.push(errorcode); g_notified = true; g_queuecheck.notify_one(); } } void loggerfunc() { // print a starting message { std::unique_lock<std::mutex> locker(g_lockprint); std::cout << "[logger]\trunning..." << std::endl; } // loop until end is signaled while(!g_done) { std::unique_lock<std::mutex> locker(g_lockqueue); while(!g_notified) // used to avoid spurious wakeups { g_queuecheck.wait(locker); } // if there are error codes in the queue process them while(!g_codes.empty()) { std::unique_lock<std::mutex> locker(g_lockprint); std::cout << "[logger]\tprocessing error: " << g_codes.front() << std::endl; g_codes.pop(); } g_notified = false; } } int main() { // initialize a random generator std::mt19937 generator((unsigned int)std::chrono::system_clock::now().time_since_epoch().count()); // start the logger std::thread loggerthread(loggerfunc); // start the working threads std::vector<std::thread> threads; for(int i = 0; i < 5; ++i) { threads.push_back(std::thread(workerfunc, i+1, std::ref(generator))); } // work for the workers to finish for(auto& t : threads) t.join(); // notify the logger to finish and wait for it g_done = true; loggerthread.join(); return 0; }
運(yùn)行這個(gè)程序,輸出如下(注意這個(gè)輸出在每次運(yùn)行下都會(huì)改變,因?yàn)槊總€(gè)工作員線程的工作和休眠的時(shí)間間隔是任意的):
[logger] running...
[worker 1] running...
[worker 2] running...
[worker 3] running...
[worker 4] running...
[worker 5] running...
[worker 1] an error occurred: 101
[worker 2] an error occurred: 201
[logger] processing error: 101
[logger] processing error: 201
[worker 5] an error occurred: 501
[logger] processing error: 501
[worker 3] an error occurred: 301
[worker 4] an error occurred: 401
[logger] processing error: 301
[logger] processing error: 401
上面的wait()有兩個(gè)重載:
其中一個(gè)只需要傳入一個(gè)unique_lock;這個(gè)重載方法釋放鎖,阻塞線程并將其添加到一個(gè)等待該條件變量的線程隊(duì)列里;該線程在收到條件變量通知信號(hào)或偽喚醒時(shí)喚醒,這時(shí)鎖被重新持有,函數(shù)返回。
另外一個(gè)在unique_lock之外,還接收一個(gè)謂詞(predicate),循環(huán)直至其返回 false;這個(gè)重載可用于避免偽喚醒,其功能類似于:
while(!predicate()) wait(lock);
于是,上面例子中布爾值g_notified可以不用,而代之以wait的接收謂詞的重載,用于確認(rèn)狀態(tài)隊(duì)列的狀態(tài)(是否為空):
void workerfunc(int id, std::mt19937& generator) { // print a starting message { std::unique_lock<std::mutex> locker(g_lockprint); std::cout << "[worker " << id << "]\trunning..." << std::endl; } // simulate work std::this_thread::sleep_for(std::chrono::seconds(1 + generator() % 5)); // simulate error int errorcode = id*100+1; { std::unique_lock<std::mutex> locker(g_lockprint); std::cout << "[worker " << id << "]\tan error occurred: " << errorcode << std::endl; } // notify error to be logged { std::unique_lock<std::mutex> locker(g_lockqueue); g_codes.push(errorcode); g_queuecheck.notify_one(); } } void loggerfunc() { // print a starting message { std::unique_lock<std::mutex> locker(g_lockprint); std::cout << "[logger]\trunning..." << std::endl; } // loop until end is signaled while(!g_done) { std::unique_lock<std::mutex> locker(g_lockqueue); g_queuecheck.wait(locker, [&](){return !g_codes.empty();}); // if there are error codes in the queue process them while(!g_codes.empty()) { std::unique_lock<std::mutex> locker(g_lockprint); std::cout << "[logger]\tprocessing error: " << g_codes.front() << std::endl; g_codes.pop(); } } }
除了可重載的wait(),還有另外兩個(gè)等待方法,都有類似的接收謂詞以避免偽喚醒的重載方法:
wait_for:阻塞線程,直至收到條件變量通知信號(hào),或指定時(shí)間段已過去。
wait_until:阻塞線程,直到收到條件變量通知信號(hào),或指定時(shí)間點(diǎn)已達(dá)到。
這兩個(gè)方法如果不傳入謂詞,會(huì)返回一個(gè)cv_status,告知是到達(dá)設(shè)定時(shí)間還是線程因條件變量通知信號(hào)或偽喚醒而喚醒。
標(biāo)準(zhǔn)庫還提供了notify_all_at_thread_exit方法,實(shí)現(xiàn)了通知其他線程某個(gè)給定線程已經(jīng)結(jié)束,以及銷毀所有thread_local實(shí)例的機(jī)制。引入這個(gè)方法的原因是,在使用thread_local時(shí), 等待一些通過非join()機(jī)制引入的線程可能造成錯(cuò)誤行為,因?yàn)樵诘却木€程恢復(fù)或可能結(jié)束之后,他們的析構(gòu)方法可能還在被調(diào)用(參看N3070和N2880)。特別的,對(duì)這個(gè)函數(shù)的一個(gè)調(diào)用,必須發(fā)生在線程剛好退出之前。下面是一個(gè)notify_all_at_thread_exit和condition_variable搭配使用來同步兩個(gè)線程的實(shí)例:
std::mutex g_lockprint; std::mutex g_lock; std::condition_variable g_signal; bool g_done; void workerfunc(std::mt19937& generator) { { std::unique_lock<std::mutex> locker(g_lockprint); std::cout << "worker running..." << std::endl; } std::this_thread::sleep_for(std::chrono::seconds(1 + generator() % 5)); { std::unique_lock<std::mutex> locker(g_lockprint); std::cout << "worker finished..." << std::endl; } std::unique_lock<std::mutex> lock(g_lock); g_done = true; std::notify_all_at_thread_exit(g_signal, std::move(lock)); } int main() { // initialize a random generator std::mt19937 generator((unsigned int)std::chrono::system_clock::now().time_since_epoch().count()); std::cout << "main running..." << std::endl; std::thread worker(workerfunc, std::ref(generator)); worker.detach(); std::cout << "main crunching..." << std::endl; std::this_thread::sleep_for(std::chrono::seconds(1 + generator() % 5)); { std::unique_lock<std::mutex> locker(g_lockprint); std::cout << "main waiting for worker..." << std::endl; } std::unique_lock<std::mutex> lock(g_lock); while(!g_done) // avoid spurious wake-ups g_signal.wait(lock); std::cout << "main finished..." << std::endl; return 0; }
如果 worker 在主線程之前結(jié)束,輸出如下:
main running...
worker running...
main crunching...
worker finished...
main waiting for worker...
main finished...
如果主線程在 worker 線程之前結(jié)束,輸出如下:
main running...
worker running...
main crunching...
main waiting for worker...
worker finished...
main finished...
關(guān)于“C++11中線程鎖和條件變量怎么應(yīng)用”這篇文章的內(nèi)容就介紹到這里,感謝各位的閱讀!相信大家對(duì)“C++11中線程鎖和條件變量怎么應(yīng)用”知識(shí)都有一定的了解,大家如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。
分享文章:C++11中線程鎖和條件變量怎么應(yīng)用-創(chuàng)新互聯(lián)
新聞來源:http://muchs.cn/article48/cedohp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供營銷型網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計(jì)公司、搜索引擎優(yōu)化、品牌網(wǎng)站設(shè)計(jì)、關(guān)鍵詞優(yōu)化、定制網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容