簡體   English   中英

我是否需要同步std :: condition_variable / condition_variable_any :: notify_one

[英]Do I need to synchronize std::condition_variable/condition_variable_any::notify_one

我是否需要同步std::condition_variable/condition_variable_any::notify_one

據我所知,如果通知丟失是可以接受的 - 可以調用notify_one不受保護(例如通過互斥鎖)。

例如,我看到了以下使用模式(抱歉,不記得在哪里):

{
    {
        lock_guard<mutex> l(m);
        // do work
    }
    c.notify_one();
}

但是,我檢查了libstdc ++來源,我看到:

condition_variable :: notify_one

void condition_variable::notify_one() noexcept
{
    int __e = __gthread_cond_signal(&_M_cond);
    // XXX not in spec
    // EINVAL
    if (__e)
        __throw_system_error(__e);
}

condition_variable_any :: notify_one

void condition_variable_any::notify_one() noexcept
{
    lock_guard<mutex> __lock(_M_mutex);
    _M_cond.notify_one();
}

這里是condition_variable_any的布局:

class condition_variable_any
{
    condition_variable _M_cond;
    mutex _M_mutex;
    // data end

即它只是condition_variable + mutex周圍的薄包裝。

所以,問題:

  1. 對於condition_variable_anycondition_variable ,不通過互斥鎖保護notify_one是不是線程安全的?
  2. 為什么condition_variable_any的實現使用額外的互斥鎖?
  3. 為什么condition_variable_any::notify_onecondition_variable::notify_one不同? 也許condition_variable::notify_one需要手動保護但是condition_variable_any::notify_one不需要? 它是libstdc ++ bug嗎?

即它只是condition_variable + mutex周圍的薄包裝。

呃沒有。 僅僅因為它具有這些類型的成員並不能使它成為一個薄的包裝器。 試着了解它的實際功能,而不僅僅是其私有成員的類型。 那里有一些非常微妙的代碼。

  1. 對於condition_variable_any或condition_variable,不通過互斥鎖保護notify_one是不是線程安全的?

是。

事實上,在鎖定互斥鎖的情況下調用notify_one()將導致等待線程被喚醒,嘗試鎖定互斥鎖,發現它仍然被通知線程鎖定,並返回休眠狀態直到互斥鎖被釋放。

如果在沒有鎖定互斥鎖的情況下調用notify_one() ,則喚醒線程可以立即運行。

2為什么condition_variable_any的實現使用額外的互斥鎖?

condition_variable_any可以與任何Lockable類型一起使用,而不僅僅是std:mutex ,但是libstdc ++中的一個使用condition_variable ,它只能與std::mutex一起使用,所以它也有一個內部的std::mutex對象。

因此condition_variable_any使用兩個互斥鎖,即用戶提供的外部互斥鎖和實現使用的內部互斥鎖。

3為什么condition_variable_any :: notify_one和condition_variable :: notify_one的實現不同? 也許condition_variable :: notify_one需要手動保護但是condition_variable_any :: notify_one不需要? 它是libstdc ++ bug嗎?

不,這不是一個錯誤。

該標准要求調用wait(mx)必須自動解鎖mx並休眠。 libstdc ++使用內部互斥鎖來提供原子性保證。 如果其他線程即將等待condition_variable_any則必須鎖定內部互斥鎖以避免錯過通知。

(1)從數據競爭的角度來看,我沒有看到任何必須由互斥鎖保護條件變量的原因。 顯然,您可能會收到冗余通知或丟失通知,但如果這是您的程序可接受或可恢復的錯誤條件,我不相信標准中的任何內容會使其成為非法。 當然,標准不會保護你免受競爭條件的影響; 程序員有責任確保競爭條件是良性的。 (當然,程序員必須不進行任何“數據競賽”,這些競爭在標准中非常具體地定義,但不直接應用於同步原語,或者召喚未定義的行為。)

(2)關於標准圖書館設施的內部實施,我無法回答這樣的問題。 當然,供應商有責任提供能夠正常工作並符合規范的庫設施。 此庫的實現可能具有一些需要互斥以避免損壞的內部狀態,或者它可能執行鎖定以避免丟失或冗余通知。 (僅僅因為你的程序可能會容忍它們,並不意味着庫的任意用戶都可以,而且一般來說我希望它們不能。)這只是在猜測我們用這個互斥鎖守護着什么。

(3) condition_variable_any適用於任何類似鎖的對象,而condition_variable專門用於處理unique_lock<mutex> 后者可能比前者更容易實現和/或更高性能,因為它具體知道它正在操作哪些類型以及它們需要什么(它們是否是微不足道的,它們是否適合高速緩存行,它們是否直接映射到一個特定平台的系統調用集,它們所暗示的圍欄或緩存一致性等等,而前者提供了一個通用的工具來操作鎖定對象而不會特別受到std::mutexstd::unique_lock<>的限制。 std::unique_lock<>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM