pbootcms网站模板|日韩1区2区|织梦模板||网站源码|日韩1区2区|jquery建站特效-html5模板网

在調用condition_variable.notify_one() 之前是否必須獲取

Do I have to acquire lock before calling condition_variable.notify_one()?(在調用condition_variable.notify_one() 之前是否必須獲取鎖?)
本文介紹了在調用condition_variable.notify_one() 之前是否必須獲取鎖?的處理方法,對大家解決問題具有一定的參考價值,需要的朋友們下面隨著小編來一起學習吧!

問題描述

我對 std::condition_variable 的使用有點困惑.我知道我必須在調用 condition_variable.wait() 之前在 mutex 上創建一個 unique_lock.我找不到的是我是否應該在調用 notify_one()notify_all() 之前獲取唯一鎖.

I am a bit confused about the use of std::condition_variable. I understand I have to create a unique_lock on a mutex before calling condition_variable.wait(). What I cannot find is whether I should also acquire a unique lock before calling notify_one() or notify_all().

cppreference.com 上的示例相互矛盾.例如,notify_one 頁面給出了這個例子:

Examples on cppreference.com are conflicting. For example, the notify_one page gives this example:

#include <iostream>
#include <condition_variable>
#include <thread>
#include <chrono>

std::condition_variable cv;
std::mutex cv_m;
int i = 0;
bool done = false;

void waits()
{
    std::unique_lock<std::mutex> lk(cv_m);
    std::cout << "Waiting... 
";
    cv.wait(lk, []{return i == 1;});
    std::cout << "...finished waiting. i == 1
";
    done = true;
}

void signals()
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << "Notifying...
";
    cv.notify_one();

    std::unique_lock<std::mutex> lk(cv_m);
    i = 1;
    while (!done) {
        lk.unlock();
        std::this_thread::sleep_for(std::chrono::seconds(1));
        lk.lock();
        std::cerr << "Notifying again...
";
        cv.notify_one();
    }
}

int main()
{
    std::thread t1(waits), t2(signals);
    t1.join(); t2.join();
}

這里的鎖不是為第一個 notify_one() 獲取的,而是為第二個 notify_one() 獲取的.查看帶有示例的其他頁面,我看到了不同的東西,主要是沒有獲取鎖.

Here the lock is not acquired for the first notify_one(), but is acquired for the second notify_one(). Looking though other pages with examples I see different things, mostly not acquiring the lock.

  • 在調用notify_one()之前我可以選擇自己鎖定互斥鎖嗎,為什么我會選擇鎖定它?
  • 在給出的示例中,為什么第一個 notify_one() 沒有鎖定,但后續調用有鎖定.這個例子是錯誤的還是有一些道理?
  • Can I choose myself to lock the mutex before calling notify_one(), and why would I choose to lock it?
  • In the example given, why is there no lock for the first notify_one(), but there is for subsequent calls. Is this example wrong or is there some rationale?

推薦答案

在調用 condition_variable::notify_one() 時不需要持有鎖,但從某種意義上說這并沒有錯它仍然是明確定義的行為,而不是錯誤.

You do not need to be holding a lock when calling condition_variable::notify_one(), but it's not wrong in the sense that it's still well defined behavior and not an error.

然而,這可能是一種悲觀化",因為任何等待線程被設為可運行(如果有)將立即嘗試獲取通知線程持有的鎖.我認為在調用 notify_one()notify_all() 時避免持有與條件變量關聯的鎖是一個很好的經驗法則.請參閱 Pthread Mutex:pthread_mutex_unlock() 消耗大量時間 例如,在調用與 notify_one() 等效的 pthread 之前釋放鎖顯著提高了性能.

However, it might be a "pessimization" since whatever waiting thread is made runnable (if any) will immediately try to acquire the lock that the notifying thread holds. I think it's a good rule of thumb to avoid holding the lock associated with a condition variable while calling notify_one() or notify_all(). See Pthread Mutex: pthread_mutex_unlock() consumes lots of time for an example where releasing a lock before calling the pthread equivalent of notify_one() improved performance measurably.

請記住,while 循環中的 lock() 調用在某些時候是必要的,因為需要在 while (!done) 循環條件檢查.但是對于 notify_one() 的調用不需要保持它.

Keep in mind that the lock() call in the while loop is necessary at some point, because the lock needs to be held during the while (!done) loop condition check. But it doesn't need to be held for the call to notify_one().

2016-02-27:大型更新解決了評論中關于是否存在競爭條件是鎖對 notify_one() 沒有幫助的一些問題稱呼.我知道這個更新晚了,因為這個問題是在大約兩年前提出的,但我想解決@Cookie 的問題,如果生產者(在這個例子中為 signals())調用notify_one() 就在消費者(本例中為waits())能夠調用wait()之前.

2016-02-27: Large update to address some questions in the comments about whether there's a race condition is the lock isn't help for the notify_one() call. I know this update is late because the question was asked almost two years ago, but I'd like to address @Cookie's question about a possible race condition if the producer (signals() in this example) calls notify_one() just before the consumer (waits() in this example) is able to call wait().

關鍵是 i 發生了什么 - 這是實際指示消費者是否有工作"要做的對象.condition_variable 只是一種讓消費者有效等待 i 更改的機制.

The key is what happens to i - that's the object that actually indicates whether or not the consumer has "work" to do. The condition_variable is just a mechanism to let the consumer efficiently wait for a change to i.

生產者在更新i時需要持有鎖,消費者在檢查i和調用condition_variable::wait()時必須持有鎖(如果它需要等待).在這種情況下,關鍵是當消費者執行此檢查和等待時,它必須是持有鎖的同一實例(通常稱為臨界區).由于臨界區在生產者更新 i 和消費者檢查并等待 i 時被保留,所以 i 沒有機會在消費者檢查 i 和調用 condition_variable::wait() 之間切換.這是正確使用條件變量的關鍵.

The producer needs to hold the lock when updating i, and the consumer must hold the lock while checking i and calling condition_variable::wait() (if it needs to wait at all). In this case, the key is that it must be the same instance of holding the lock (often called a critical section) when the consumer does this check-and-wait. Since the critical section is held when the producer updates i and when the consumer checks-and-waits on i, there is no opportunity for i to change between when the consumer checks i and when it calls condition_variable::wait(). This is the crux for a proper use of condition variables.

C++ 標準規定,當使用謂詞調用時,condition_variable::wait() 的行為如下(如本例所示):

The C++ standard says that condition_variable::wait() behaves like the following when called with a predicate (as in this case):

while (!pred())
    wait(lock);

消費者檢查i時可能出現兩種情況:

There are two situations that can occur when the consumer checks i:

  • 如果i為0,則消費者調用cv.wait(),則iwait(lock) 部分實現被調用 - 正確使用鎖確保了這一點.在這種情況下,生產者沒有機會在其 while 循環中調用 condition_variable::notify_one() 直到消費者調用 cv.wait(lk,[]{return i == 1;}) (并且 wait() 調用已經完成了正確捕捉"通知所需的一切 - wait() 在它完成之前不會釋放鎖).所以在這種情況下,消費者不會錯過通知.

  • if i is 0 then the consumer calls cv.wait(), then i will still be 0 when the wait(lock) part of the implementation is called - the proper use of the locks ensures that. In this case the producer has no opportunity to call the condition_variable::notify_one() in its while loop until after the consumer has called cv.wait(lk, []{return i == 1;}) (and the wait() call has done everything it needs to do to properly 'catch' a notify - wait() won't release the lock until it has done that). So in this case, the consumer cannot miss the notification.

如果當消費者調用cv.wait()i已經為1,則wait(lock)部分永遠不會調用實現,因為 while (!pred()) 測試將導致內部循環終止.在這種情況下,何時調用 notify_one() 無關緊要 - 消費者不會阻塞.

if i is already 1 when the consumer calls cv.wait(), the wait(lock) part of the implementation will never be called because the while (!pred()) test will cause the internal loop to terminate. In this situation it doesn't matter when the call to notify_one() occurs - the consumer will not block.

此處的示例確實具有額外的復雜性,即使用 done 變量向生產者線程發信號通知消費者已識別 i == 1,但我不要認為這根本不會改變分析,因為對 done 的所有訪問(用于讀取和修改)都是在涉及 icondition_variable.

The example here does have the additional complexity of using the done variable to signal back to the producer thread that the consumer has recognized that i == 1, but I don't think this changes the analysis at all because all of the access to done (for both reading and modifying) are done while in the same critical sections that involve i and the condition_variable.

如果你看看@eh9 指出的問題,同步使用 std::atomic 和 std::condition_variable 不可靠,您看到競爭條件.但是,該問題中發布的代碼違反了使用條件變量的基本規則之一:在執行檢查和等待時,它不包含單個臨界區.

If you look at the question that @eh9 pointed to, Sync is unreliable using std::atomic and std::condition_variable, you will see a race condition. However, the code posted in that question violates one of the fundamental rules of using a condition variable: It does not hold a single critical section when performing a check-and-wait.

在該示例中,代碼如下所示:

In that example, the code looks like:

if (--f->counter == 0)      // (1)
    // we have zeroed this fence's counter, wake up everyone that waits
    f->resume.notify_all(); // (2)
else
{
    unique_lock<mutex> lock(f->resume_mutex);
    f->resume.wait(lock);   // (3)
}

您會注意到#3 處的wait() 是在保持f->resume_mutex 的同時執行的.但是在第 1 步檢查 wait() 是否有必要沒有在持有該鎖的情況下完成(更不用說連續檢查和 -等待),這是正確使用條件變量的要求).我相信對該代碼片段有問題的人認為,由于 f->counter 是一個 std::atomic 類型,這將滿足要求.但是,std::atomic 提供的原子性不會擴展到對 f->resume.wait(lock) 的后續調用.在此示例中,在檢查 f->counter 時(步驟 1)和調用 wait() 時(步驟 3)之間存在競爭.

You will notice that the wait() at #3 is performed while holding f->resume_mutex. But the check for whether or not the wait() is necessary at step #1 is not done while holding that lock at all (much less continuously for the check-and-wait), which is a requirement for proper use of condition variables). I believe that the person who has the problem with that code snippet thought that since f->counter was a std::atomic type this would fulfill the requirement. However, the atomicity provided by std::atomic doesn't extend to the subsequent call to f->resume.wait(lock). In this example, there is a race between when f->counter is checked (step #1) and when the wait() is called (step #3).

這個問題的例子中不存在那個種族.

That race does not exist in this question's example.

這篇關于在調用condition_variable.notify_one() 之前是否必須獲取鎖?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!

【網站聲明】本站部分內容來源于互聯網,旨在幫助大家更快的解決問題,如果有圖片或者內容侵犯了您的權益,請聯系我們刪除處理,感謝您的支持!

相關文檔推薦

What is the fastest way to transpose a matrix in C++?(在 C++ 中轉置矩陣的最快方法是什么?)
Sorting zipped (locked) containers in C++ using boost or the STL(使用 boost 或 STL 在 C++ 中對壓縮(鎖定)容器進行排序)
Rotating a point about another point (2D)(圍繞另一個點旋轉一個點 (2D))
Image Processing: Algorithm Improvement for #39;Coca-Cola Can#39; Recognition(圖像處理:Coca-Cola Can 識別的算法改進)
How do I construct an ISO 8601 datetime in C++?(如何在 C++ 中構建 ISO 8601 日期時間?)
Sort list using STL sort function(使用 STL 排序功能對列表進行排序)
主站蜘蛛池模板: 烟雾净化器-滤筒除尘器-防爆除尘器-除尘器厂家-东莞执信环保科技有限公司 | 无菌水质袋-NASCO食品无菌袋-Whirl-Pak无菌采样袋-深圳市慧普德贸易有限公司 | 山东限矩型液力偶合器_液力耦合器易熔塞厂家-淄博市汇川源机械厂 | 食药成分检测_调料配方还原_洗涤剂化学成分分析_饲料_百检信息科技有限公司 | 成都LED显示屏丨室内户外全彩led屏厂家方案报价_四川诺显科技 | IHDW_TOSOKU_NEMICON_EHDW系列电子手轮,HC1系列电子手轮-上海莆林电子设备有限公司 | 缓蚀除垢剂_循环水阻垢剂_反渗透锅炉阻垢剂_有机硫化物-郑州威大水处理材料有限公司 | 防爆电机_防爆电机型号_河南省南洋防爆电机有限公司 | 铝箔袋,铝箔袋厂家,东莞铝箔袋,防静电铝箔袋,防静电屏蔽袋,防静电真空袋,真空袋-东莞铭晋让您的产品与众不同 | 开业庆典_舞龙舞狮_乔迁奠基仪式_开工仪式-神挚龙狮鼓乐文化传媒 | 管理会计网-PCMA初级管理会计,中级管理会计考试网站 | NM-02立式吸污机_ZHCS-02软轴刷_二合一吸刷软轴刷-厦门地坤科技有限公司 | 富森高压水枪-柴油驱动-养殖场高压清洗机-山东龙腾环保科技有限公司 | 淄博不锈钢无缝管,淄博不锈钢管-鑫门物资有限公司 | 会议会展活动拍摄_年会庆典演出跟拍_摄影摄像直播-艾木传媒 | 金属软管_不锈钢金属软管_巩义市润达管道设备制造有限公司 | 信阳网站建设专家-信阳时代网联-【信阳网站建设百度推广优质服务提供商】信阳网站建设|信阳网络公司|信阳网络营销推广 | 中天寰创-内蒙古钢结构厂家|门式刚架|钢结构桁架|钢结构框架|包头钢结构煤棚 | 六自由度平台_六自由度运动平台_三自由度摇摆台—南京全控科技 | 深圳彩钢板_彩钢瓦_岩棉板_夹芯板_防火复合彩钢板_长鑫 | 干粉砂浆设备-干粉砂浆生产线-干混-石膏-保温砂浆设备生产线-腻子粉设备厂家-国恒机械 | 媒介云-全网整合营销_成都新闻媒体发稿_软文发布平台 | 上海公众号开发-公众号代运营公司-做公众号的公司企业服务商-咏熠软件 | 杜康白酒加盟_杜康酒代理_杜康酒招商加盟官网_杜康酒厂加盟总代理—杜康酒神全国运营中心 | 北京普辉律师事务所官网_北京律师24小时免费咨询|法律咨询 | 南京雕塑制作厂家-不锈钢雕塑制作-玻璃钢雕塑制作-先登雕塑厂 | 东莞爱加真空科技有限公司-进口真空镀膜机|真空镀膜设备|Polycold维修厂家 | 蓝米云-专注于高性价比香港/美国VPS云服务器及海外公益型免费虚拟主机 | 机房监控|动环监控|动力环境监控系统方案产品定制厂家 - 迈世OMARA | 氢氧化钾厂家直销批发-济南金昊化工有限公司 | SRRC认证|CCC认证|CTA申请_IMEI|MAC地址注册-英利检测 | 电加热导热油炉-空气加热器-导热油加热器-翅片电加热管-科安达机械 | 真空包装机-诸城市坤泰食品机械有限公司| PSI渗透压仪,TPS酸度计,美国CHAI PCR仪,渗透压仪厂家_价格,微生物快速检测仪-华泰和合(北京)商贸有限公司 | 威廉希尔WilliamHill·足球(中国)体育官方网站 | 美侍宠物-专注宠物狗及宠物猫训练|喂养|医疗|繁育|品种|价格 | 北京森语科技有限公司-模型制作专家-展览展示-沙盘模型设计制作-多媒体模型软硬件开发-三维地理信息交互沙盘 | 撕碎机_轮胎破碎机_粉碎机_回收生产线厂家_东莞华达机械有限公司 | 手机存放柜,超市储物柜,电子储物柜,自动寄存柜,行李寄存柜,自动存包柜,条码存包柜-上海天琪实业有限公司 | 东莞压铸厂_精密压铸_锌合金压铸_铝合金压铸_压铸件加工_东莞祥宇金属制品 | WF2户外三防照明配电箱-BXD8050防爆防腐配电箱-浙江沃川防爆电气有限公司 |