您好,登錄后才能下訂單哦!
今天小編給大家分享一下C++11 condition_variable條件變量怎么使用的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。
condition_variable是一個類,常和mutex搭配使用。
condition_variable類是一個同步原語,可用于阻塞一個線程或同時阻止多個線程,直到另一個線程修改共享變量并通知condition_variable。
防止多線程場景下,共享變量混亂。
理解條件變量要先理解三個概念:
鎖 (鎖住共享變量,線程獨占)
wait
等待 (等待通知條件變量,變化的共享變量是否滿足條件)
notify
通知 (通知等待的條件變量,共享變量發送變化)
void wait( std::unique_lockstd::mutex& lock ); //Predicate是lambda表達式。 template< class Predicate > void wait( std::unique_lockstd::mutex& lock, Predicate pred ); //以上二者都被notify_one())或notify_broadcast()喚醒,但是 //第二種方式是喚醒后也要滿足Predicate的條件。 //如果不滿足條件,繼續解鎖互斥量,然后讓線程處于阻塞或等待狀態。 //第二種等價于 while (!pred()) { wait(lock); }
condition_variable必定至少有兩方,一方是資源修改線程,一方是資源等待線程。就跟打籃球一樣,同時籃球只會在一個人手中,投籃后就釋放了籃球所有權,其他方就會搶奪籃球所有權。
獲取一個mutex使用 std::unique_lock< std::mutex >
保持鎖定狀態,修改共享變量
condition_variable對象執行notify_one或者notify_all(notify_one/notify_all執行前可以釋放鎖)
獲取一個mutex使用 std::unique_lock< std::mutex > unlock用于保護要修改的共享變量
檢查條件變量,
(1)條件變量滿足,線程繼續執行
(2)條件變量不滿足,wait會釋放unlock鎖,并掛起線程。
當notify通知條件變量、超時過期或發生虛假喚醒時,線程被喚醒,互斥鎖unlock被原子地重新獲取。然后,線程應該檢查條件,如果喚醒是假的,則繼續等待
當wait第一次執行是,條件已經滿足,則程序不會阻塞(即無需notify),會直接向下執行。(僅為說明3.2 中第2點(1)的情況)
#include <iostream> #include <string> #include <thread> #include <mutex> #include <condition_variable> using namespace std; std::mutex m; std::condition_variable cv; std::string data; bool ready = false; bool processed = false; void worker_thread() { std::cout << "3、worker_thread子線程開始執行" << endl; // Wait until main() sends data std::unique_lock<std::mutex> lk(m); std::cout << "4、worker_thread子線程獲取到鎖,條件滿足無需notify,不阻塞向下執行" << endl; cv.wait(lk, []{return ready;}); // after the wait, we own the lock. data += " after processing"; // Send data back to main() processed = true; std::cout << "5、Worker thread signals data processing completed\n"; // Manual unlocking is done before notifying, to avoid waking up // the waiting thread only to block again (see notify_one for details) lk.unlock(); std::cout << "6、worker_thread子線程交出執行權限,主線程執行" << endl; std::this_thread::sleep_for(std::chrono::milliseconds(2000)); cv.notify_one(); std::cout << "9、worker_thread調用 notify_one" << endl; } int main() { std::thread worker(worker_thread); std::cout << "1、主線程開始執行" << std::endl; data = "Example data"; // send data to the worker thread { //std::this_thread::sleep_for(std::chrono::milliseconds(1000)); std::lock_guard<std::mutex> lk(m); ready = true; } std::cout << "2、鎖已經釋放了,主線程休眠,子線程執行" << std::endl; std::this_thread::sleep_for(std::chrono::milliseconds(1000)); //cv.notify_one(); { std::cout << "7、主線程data:" << data << endl; std::unique_lock<std::mutex> lk(m); std::cout << "8、主線程條件滿足無需notify" << endl; cv.wait(lk, []{return processed;}); } worker.join(); std::cout << "10、主線程結束" << endl; }
執行結果:
#include <iostream> #include <string> #include <thread> #include <mutex> #include <condition_variable> using namespace std; std::mutex m; std::condition_variable cv; std::string data; bool ready = false; bool processed = false; void worker_thread() { std::cout << "3、worker_thread子線程開始執行" << endl; // Wait until main() sends data std::unique_lock<std::mutex> lk(m); std::cout << "4、worker_thread子線程獲取到鎖,條件不滿足,釋放lk鎖,子線程阻塞" << endl; cv.wait(lk, []{return ready;}); std::cout << "8、worker_thread子線程獲取到鎖,子線程繼續執行" << endl; // after the wait, we own the lock. data += " after processing"; // Send data back to main() processed = true; std::cout << "9、Worker thread signals data processing completed\n"; // Manual unlocking is done before notifying, to avoid waking up // the waiting thread only to block again (see notify_one for details) lk.unlock(); std::this_thread::sleep_for(std::chrono::milliseconds(5000)); std::cout << "10、worker_thread調用 notify_one通知主線程執行" << endl; cv.notify_one(); } int main() { std::thread worker(worker_thread); std::cout << "1、主線程開始執行" << std::endl; data = "Example data"; // send data to the worker thread { std::cout << "2、主線程休眠,子線程進入執行" << std::endl; std::this_thread::sleep_for(std::chrono::milliseconds(1000)); std::cout << "5、主線程結束休眠,主線程獲取lk鎖,進入執行" << std::endl; std::lock_guard<std::mutex> lk(m); ready = true; } std::cout << "6、主線程釋放lk,調用notify通知子線程" << std::endl; cv.notify_one(); { std::cout << "7、由于主線程的執行時鐘周期未結束,繼續執行主線程獲取lk, wait檢查條件不滿足,釋放鎖" << endl; std::unique_lock<std::mutex> lk(m); cv.wait(lk, []{return processed;}); } worker.join(); std::cout << "11、主線程結束" << endl; }
執行結果:
這里notify執行后不一定立即執行子線程,如果cpu執行時鐘周期未結束,則主線程會繼續執行. 所以7,8,9,10順序可能變化參見4.3
同時4.1也會因為cpu時鐘周期,執行順序有所變動。
#include <iostream> #include <string> #include <thread> #include <mutex> #include <condition_variable> using namespace std; std::mutex m; std::condition_variable cv; std::string data; bool ready = false; bool processed = false; void worker_thread() { std::cout << "3、worker_thread子線程開始執行" << endl; // Wait until main() sends data std::unique_lock<std::mutex> lk(m); std::cout << "4、worker_thread子線程獲取到鎖,條件不滿足,釋放lk鎖,子線程阻塞" << endl; cv.wait(lk, []{return ready;}); std::cout << "8、worker_thread子線程獲取到鎖,子線程繼續執行" << endl; // after the wait, we own the lock. data += " after processing"; // Send data back to main() processed = true; std::cout << "9、Worker thread signals data processing completed\n"; // Manual unlocking is done before notifying, to avoid waking up // the waiting thread only to block again (see notify_one for details) lk.unlock(); std::cout << "10、worker_thread調用 notify_one通知主線程執行" << endl; cv.notify_one(); } int main() { std::thread worker(worker_thread); std::cout << "1、主線程開始執行" << std::endl; data = "Example data"; // send data to the worker thread { std::cout << "2、主線程休眠,子線程進入執行" << std::endl; std::this_thread::sleep_for(std::chrono::milliseconds(1000)); std::cout << "5、主線程結束休眠,主線程獲取lk鎖,進入執行" << std::endl; std::lock_guard<std::mutex> lk(m); ready = true; } std::cout << "6、主線程釋放lk,調用notify通知子線程" << std::endl; cv.notify_one(); { for(int i = 0; i< 10000000; i++) { int j = i; } std::cout << "7、由于主線程的執行時鐘周期未結束,繼續執行主線程獲取lk, wait檢查條件不滿足,釋放鎖" << endl; std::unique_lock<std::mutex> lk(m); cv.wait(lk, []{return processed;}); } worker.join(); std::cout << "11、主線程結束" << endl; }
執行結果:
以上就是“C++11 condition_variable條件變量怎么使用”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。