最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++ std::condition_variable 條件變量用法解析

 更新時間:2023年09月28日 11:11:42   作者:戀喵大鯉魚  
condition_variable(條件變量)是 C++11 中提供的一種多線程同步機(jī)制,它允許一個或多個線程等待另一個線程發(fā)出通知,以便能夠有效地進(jìn)行線程同步,這篇文章主要介紹了C++ std::condition_variable 條件變量用法,需要的朋友可以參考下

1.簡介

condition_variable(條件變量)是 C++11 中提供的一種多線程同步機(jī)制,它允許一個或多個線程等待另一個線程發(fā)出通知,以便能夠有效地進(jìn)行線程同步。

condition_variable 需要與 mutex(互斥鎖)一起使用。當(dāng)線程需要等待某個條件變成真時,它會獲取一個互斥鎖,然后在條件變量上等待,等待期間會自動釋放互斥鎖。另一個線程在滿足條件后會獲取相同的互斥鎖,并調(diào)用條件變量的 notify_one() 或 notify_all() 函數(shù)來喚醒等待的線程。

條件變量是實現(xiàn)復(fù)雜線程同步和通信的重要工具,用于避免線程的忙等待和提高性能。

2.等待函數(shù)

condition_variable 有三個等待函數(shù):wait()、wait_for() 和 wait_util()。

這三個函數(shù)需要與互斥鎖一起使用,以互斥的方式訪問共享資源,并阻塞線程,等待通知。

wait()

void wait(std::unique_lock<std::mutex>& lock);
template <class Predicate>  void wait (unique_lock<mutex>& lck, Predicate pred);

wait() 函數(shù)用于阻塞線程并等待喚醒。

在調(diào)用 wait() 之前,必須獲取一個獨(dú)占鎖(std::unique_lock)并將它傳遞給 wait() 函數(shù)。

如果條件變量當(dāng)前不滿足,線程將被阻塞,同時釋放鎖,使得其他線程可以繼續(xù)執(zhí)行。

當(dāng)另一個線程調(diào)用 notify_one() 或 notify_all() 來通知條件變量時,被阻塞的線程將被喚醒,并再次嘗試獲取鎖。

wait() 函數(shù)返回時,鎖會再次被持有。

wait() 函數(shù)有一個帶謂詞的版本,可以簡化對條件的判斷。僅僅有當(dāng) pred 條件為 false 時調(diào)用 wait() 才會阻塞當(dāng)前線程,解決了的喚醒丟失問題。而且在收到其它線程的通知后僅僅有當(dāng) pred 為 true 時才會被解除堵塞,解決了虛假喚醒的問題。

用法如下:

std::condition_variable cv;
std::mutex mtx;
bool condition = false;
void worker() {
    std::unique_lock<std::mutex> lock(mtx);
    cv.wait(lock, []{ return condition; }); // 等待條件滿足
    // ...
}

wait_for()

template <class Rep, class Period>
cv_status wait_for(std::unique_lock<std::mutex>& lock, const std::chrono::duration<Rep, Period>& rel_time);
template <class Rep, class Period, class Predicate>
bool wait_for (unique_lock<mutex>& lck, const chrono::duration<Rep,Period>& rel_time, Predicate pred);

wait_for() 函數(shù)用于阻塞線程并等待喚醒,但與 wait() 不同,它可以設(shè)置一個超時時間。

在調(diào)用 wait_for() 之前,必須獲取一個獨(dú)占鎖(std::unique_lock)并將它傳遞給 wait_for() 函數(shù)。

如果條件變量在指定的超時時間內(nèi)變?yōu)闈M足,線程將被喚醒,并且 wait_for() 返回 cv_status::no_timeout。

如果超時時間到期且仍未收到喚醒通知,wait_for() 返回 cv_status::timeout,線程繼續(xù)執(zhí)行。

wait_for() 函數(shù)同樣有一個謂詞版本,用法同 wait() 函數(shù)。

wait_until()

template <class Clock, class Duration>
cv_status wait_until(std::unique_lock<std::mutex>& lock, const std::chrono::time_point<Clock, Duration>& abs_time);
template <class Clock, class Duration, class Predicate>
bool wait_until(unique_lock<mutex>& lck, const chrono::time_point<Clock,Duration>& abs_time, Predicate pred);

wait_until 接受一個絕對時間點(diǎn)作為參數(shù)。

線程將等待直到指定的絕對時間點(diǎn),如果在該時間點(diǎn)之前條件變量滿足,它將返回并繼續(xù)執(zhí)行。

如果到達(dá)指定時間點(diǎn)仍未收到喚醒通知,wait_until 返回 cv_status::timeout,線程繼續(xù)執(zhí)行。

wait_until() 函數(shù)同樣有一個謂詞版本,用法同 wait() 函數(shù)。

3.通知函數(shù)

通知函數(shù)有 notify_one() 和 notify_all()。

這兩個函數(shù)都用于喚醒等待線程,以便它們可以繼續(xù)執(zhí)行。notify_all() 用于廣播通知,以確保所有等待線程都有機(jī)會檢查條件是否滿足,而 notify_one() 用于選擇性通知一個等待線程。

notify_one()

void notify_one() noexcept;

notify_one() 用于喚醒等待在條件變量上的單個線程。

如果有多個線程在條件變量上等待,只有其中一個線程會被喚醒,具體是哪個線程 C++ 標(biāo)準(zhǔn)并未明確,所以是不確定的。

被喚醒的線程將嘗試獲取與條件變量關(guān)聯(lián)的互斥鎖,一旦成功獲取鎖,它可以繼續(xù)執(zhí)行。

notify_all()

void notify_all() noexcept;

notify_all() 用于喚醒等待在條件變量上的所有線程。

如果有多個線程在條件變量上等待,所有這些線程都會被喚醒。

喚醒的線程將競爭獲取與條件變量關(guān)聯(lián)的互斥鎖,然后可以繼續(xù)執(zhí)行。

4.注意事項

在使用 condition_variable 時需要注意以下幾點(diǎn):

1.需要與互斥量一起使用,等待前要鎖定互斥量

std::condition_variable 必須與 std::unique_lock 一起使用,需要在持有 mutex 的情況下調(diào)用 wait() 函數(shù),以確保在線程等待條件時互斥訪問共享資源,從而避免競態(tài)條件(Race Condition)。共享資源包括等待的條件,以及線程等待隊列。

2.注意虛假喚醒和喚醒丟失

虛假喚醒(spurious wakeup)指一個或多個線程被喚醒,但沒有實際的條件變化或通知發(fā)生。這些線程被認(rèn)為是"虛假喚醒"。

虛假喚醒通常由操作系統(tǒng)或 C++ 標(biāo)準(zhǔn)庫的實現(xiàn)引發(fā),這是多線程環(huán)境中的一種正常行為。雖然它可能看起來不合理,但是在某些情況下,它是必要的,因為操作系統(tǒng)或標(biāo)準(zhǔn)庫可能需要在內(nèi)部執(zhí)行一些資源管理或線程調(diào)度操作,這可能導(dǎo)致線程被喚醒。

喚醒丟失(wakeup loss)指發(fā)送方在接收方進(jìn)入等待狀態(tài)之前發(fā)送通知,結(jié)果就是導(dǎo)致通知消失。

為了解決虛假喚醒和喚醒丟失的問題,需要使用一個變量(通常是 bool 類型的變量)來表示等待的條件,線程在等待前和等待后檢查該條件是否滿足。

3.不要忽略 wait_for 和 wait_until 函數(shù)返回值

wait_for 和 wait_until 函數(shù)的返回值應(yīng)該被檢查,以判斷是因為超時還是因為被通知而返回。

4.不要在鎖內(nèi)部執(zhí)行耗時操作

盡量避免在鎖內(nèi)部執(zhí)行可能會阻塞或耗時較長的操作,因為這會導(dǎo)致其他線程在等待條件時被阻塞。

5.避免死鎖

確保你的線程同步邏輯不會導(dǎo)致死鎖,例如,不要在持有互斥鎖的情況下調(diào)用可能再次嘗試獲取同一個鎖的函數(shù)。

6.小心使用 std::condition_variable_any

std::condition_variable_any 是通用的條件變量,可以與不同類型的互斥量一起使用。但要小心,因為它的性能可能不如與 std::mutex 直接關(guān)聯(lián)的 std::condition_variable。

總之,在多線程編程中使用 std::condition_variable 時,要謹(jǐn)慎考慮同步邏輯,確保線程安全性,防止死鎖,以及正確處理條件等待和通知。多線程編程通常很復(fù)雜,需要仔細(xì)思考和測試。

5.使用示例

#include <iostream>   
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex mtx; 			// 全局相互排斥鎖。
std::condition_variable cv; // 全局條件變量。
bool ready = false;			// 全局標(biāo)志位。
void print_id(int id) {
    std::unique_lock <std::mutex> lck(mtx);
    // 假設(shè)標(biāo)志位不為 true, 則等待...
    while (!ready){
        // 當(dāng)前線程被堵塞,等待被喚醒。
        cv.wait(lck);
    }
    // 線程被喚醒, 繼續(xù)往下運(yùn)行打印線程編號id。
    std::cout << "thread " << id << std::endl;
}
void go() {
    std::unique_lock<std::mutex> lck(mtx);
    ready = true;       // 設(shè)置全局標(biāo)志位為 true.
    cv.notify_all();    // 喚醒全部線程.
}
int main() {
    std::thread threads[10];
    for (int i = 0; i < 10; ++i) {
        threads[i] = std::thread(print_id, i);
    }
    std::cout << "10 threads ready to race..." << std::endl;
    go();
    // 等待所有線程執(zhí)行完成。
    for (auto& th : threads) {
        th.join();
    }
    return 0;
}

編譯運(yùn)行輸出:

10 threads ready to race...
thread 0
thread 1
thread 2
thread 9
thread 4
thread 6
thread 5
thread 7
thread 8
thread 3

多次運(yùn)行結(jié)果是不定的,因為線程調(diào)度的順序是不確定的。

參考文獻(xiàn)

std::condition_variable - cplusplus.com

notify_one() choose which thread to unblock?

c++ - Why ‘wait with predicate’ solves the ‘lost wakeup’ - stackoverflow

到此這篇關(guān)于C++ std::condition_variable 條件變量用法的文章就介紹到這了,更多相關(guān)C++ std::condition_variable 條件變量內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 深入遍歷二叉樹的各種操作詳解(非遞歸遍歷)

    深入遍歷二叉樹的各種操作詳解(非遞歸遍歷)

    本篇文章是對遍歷二叉樹的各種操作進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • 史上最強(qiáng)C語言分支和循環(huán)教程詳解

    史上最強(qiáng)C語言分支和循環(huán)教程詳解

    這篇文章主要介紹了史上最強(qiáng)C語言分支和循環(huán)教程詳解,本文通過代碼演示給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-11-11
  • C++實現(xiàn)LeetCode(23.合并k個有序鏈表)

    C++實現(xiàn)LeetCode(23.合并k個有序鏈表)

    這篇文章主要介紹了C++實現(xiàn)LeetCode(23.合并k個有序鏈表),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • C語言實現(xiàn)單鏈表的示例詳解

    C語言實現(xiàn)單鏈表的示例詳解

    給需要考研的同學(xué)一個參考,單鏈表作為常見數(shù)據(jù)結(jié)構(gòu)的一種,這里記錄C語言實現(xiàn)單鏈表,文章通過代碼示例介紹的非常詳細(xì),具有一頂?shù)膮⒖純r值,需要的朋友可以參考下
    2023-09-09
  • C/C++函數(shù)調(diào)用的幾種方式總結(jié)

    C/C++函數(shù)調(diào)用的幾種方式總結(jié)

    本篇文章主要是對C/C++函數(shù)調(diào)用的幾種方式進(jìn)行了詳細(xì)的總結(jié)介紹,需要的朋友可以過來參考下,希望對大家有所幫助
    2013-12-12
  • C語言中壓縮字符串的簡單算法小結(jié)

    C語言中壓縮字符串的簡單算法小結(jié)

    這篇文章主要介紹了C語言中可用于實現(xiàn)字符串壓縮的簡單算法小結(jié),列舉了包括哈夫曼算法等三個核心的程序?qū)崿F(xiàn)算法,需要的朋友可以參考下
    2016-03-03
  • C語言*與&在操作線性表的作用詳解

    C語言*與&在操作線性表的作用詳解

    本文主要介紹了C語言*與&在操作線性表的作用詳解,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • C++函數(shù)模板與重載解析超詳細(xì)講解

    C++函數(shù)模板與重載解析超詳細(xì)講解

    模板是C++最重要的設(shè)計。這篇文章講的是函數(shù)模板,只是簡單介紹模板的一些功能,關(guān)于模板的更多的內(nèi)容會在類模板中詳細(xì)介紹。文章還著重介紹了重載解析過程
    2022-08-08
  • C++從文件中提取英文單詞的實現(xiàn)方法

    C++從文件中提取英文單詞的實現(xiàn)方法

    本文主要介紹了C++從文件中提取英文單詞的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • C++智能指針shared_ptr

    C++智能指針shared_ptr

    這篇文章主要介紹了C++智能指針shared_ptr,C++11中包括shared_ptr在內(nèi)的多種指針,都是模板類型,意味著使用者可以指定想要操作的類型下文從shared_ptr創(chuàng)建方式展開全文,介紹詳細(xì)具有一的參考價值,需要的小伙伴可以參考一下
    2022-03-03

最新評論

西贡区| 阜阳市| 宜兴市| 禹城市| 沭阳县| 台前县| 福安市| 汤阴县| 杭锦后旗| 安仁县| 平顺县| 元氏县| 新平| 北票市| 那曲县| 称多县| 泽库县| 永平县| 钦州市| 甘谷县| 金秀| 教育| 定襄县| 麻栗坡县| 苍山县| 绩溪县| 南岸区| 白山市| 马关县| 商河县| 许昌县| 嘉禾县| 河北区| 阜平县| 凤冈县| 迁西县| 天门市| 军事| 斗六市| 云安县| 横山县|