- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我对std::condition_variable
的使用有点困惑.我知道我必须创建一个 unique_lock
在 mutex
调用前 condition_variable.wait()
.我找不到的是我是否也应该在调用 notify_one()
之前获取唯一锁或 notify_all()
.
关于 cppreference.com 的示例是矛盾的。例如,notify_one page给出这个例子:
#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... \n";
cv.wait(lk, []{return i == 1;});
std::cout << "...finished waiting. i == 1\n";
done = true;
}
void signals()
{
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "Notifying...\n";
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...\n";
cv.notify_one();
}
}
int main()
{
std::thread t1(waits), t2(signals);
t1.join(); t2.join();
}
notify_one()
获取锁,但为第二个
notify_one()
获得.通过示例查看其他页面,我看到了不同的东西,主要是没有获取锁。
notify_one()
,为什么我会选择锁定它? notify_one()
没有锁,但有用于后续调用。这个例子是错误的还是有一些理由? 最佳答案
拨打 condition_variable::notify_one()
时不需要持有锁,但从某种意义上说它仍然是明确定义的行为而不是错误,这并没有错。
然而,这可能是一种“悲观化”,因为任何等待线程变为可运行的(如果有)都会立即尝试获取通知线程持有的锁。我认为在调用 notify_one()
时避免持有与条件变量关联的锁是一个很好的经验法则。或 notify_all()
.见 Pthread Mutex: pthread_mutex_unlock() consumes lots of time例如,在调用与 notify_one()
等效的 pthread 之前释放锁显着提高了性能。
请记住,lock()
调用 while
在某些时候循环是必要的,因为锁需要在 while (!done)
期间保持。循环条件检查。但是拨打notify_one()
不需要保持。 .
2016-02-27 :解决评论中关于是否存在竞争条件的一些问题的大更新,锁定对 notify_one()
没有帮助打电话。我知道这个更新晚了,因为这个问题是在两年前提出的,但我想解决@Cookie 关于可能的竞争条件的问题,如果生产者(在本例中为 signals()
)调用 notify_one()
就在消费者(在本例中为 waits()
)能够调用 wait()
之前.
关键是i
会发生什么- 这是实际指示消费者是否有“工作”要做的对象。 condition_variable
只是一种让消费者高效等待更改的机制 i
.
生产者更新时需要持有锁i
,并且消费者在检查时必须持有锁i
并调用 condition_variable::wait()
(如果它需要等待)。在这种情况下,关键是当消费者执行此检查和等待时,它必须是持有锁(通常称为临界区)的同一个实例。由于生产者更新时会保留临界区 i
当消费者检查并等待 i
时,没有机会i
在消费者检查之间进行更改 i
当它调用 condition_variable::wait()
时.这是正确使用条件变量的关键。
C++ 标准规定,当使用谓词调用时,condition_variable::wait() 的行为如下(在本例中):
while (!pred())
wait(lock);
i
时可能会出现两种情况:
i
为 0 则消费者调用 cv.wait()
,然后 i
wait(lock)
时仍为 0实现的一部分被称为 - 正确使用锁确保了这一点。在这种情况下,生产者没有机会调用 condition_variable::notify_one()
在其 while
循环直到消费者调用 cv.wait(lk, []{return i == 1;})
(并且 wait()
调用已经完成了正确“捕获”通知所需的一切 - wait()
在完成之前不会释放锁)。所以在这种情况下,消费者不能错过通知。 i
当消费者调用 cv.wait()
时已经是 1 , wait(lock)
部分实现永远不会被调用,因为 while (!pred())
测试将导致内部循环终止。在这种情况下,何时调用 notify_one() 无关紧要 - 消费者不会阻塞。 done
的额外复杂性。变量以向生产者线程发回信号,表明消费者已认识到
i == 1
,但我认为这根本不会改变分析,因为所有访问
done
(用于阅读和修改)是在涉及
i
的相同临界区中完成的。和
condition_variable
.
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)
}
wait()
在#3 处执行同时持有
f->resume_mutex
.但检查是否
wait()
在第 1 步是必要的,而根本没有持有该锁(对于检查和等待而言,连续性要少得多),这是正确使用条件变量的要求)。我相信那个代码片段有问题的人认为,自从
f->counter
是
std::atomic
键入这将满足要求。但是,
std::atomic
提供的原子性不会扩展到对
f->resume.wait(lock)
的后续调用.在这个例子中,在
f->counter
之间存在竞争。检查(步骤#1)并且当
wait()
被调用(步骤#3)。
关于c++ - 在调用condition_variable.notify_one() 之前是否必须获取锁?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17101922/
我需要您在以下方面提供帮助。近一个月来,我一直在阅读有关任务和异步的内容。 我想尝试在一个简单的 wep api 项目中实现我新获得的知识。我有以下方法,并且它们都按预期工作: public Htt
我的可执行 jar 中有一个模板文件 (.xls)。不需要在运行时我需要为这个文件创建 100 多个副本(稍后将唯一地附加)。用于获取 jar 文件中的资源 (template.xls)。我正在使用
我在查看网站的模型代码时对原型(prototype)有疑问。我知道这对 Javascript 中的继承很有用。 在这个例子中... define([], function () { "use
影响我性能的前三项操作是: 获取滚动条 获取偏移高度 Ext.getStyle 为了解释我的应用程序中发生了什么:我有一个网格,其中有一列在每个单元格中呈现网格。当我几乎对网格的内容做任何事情时,它运
我正在使用以下函数来获取 URL 参数。 function gup(name, url) { name = name.replace(/[\[]/, '\\\[').replace(/[\]]/,
我最近一直在使用 sysctl 来做很多事情,现在我使用 HW_MACHINE_ARCH 变量。我正在使用以下代码。请注意,当我尝试获取其他变量 HW_MACHINE 时,此代码可以完美运行。我还认为
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 关闭 9 年前。 要求提供代码的问题必须表现出对所解决问题的最低限度的理解。包括尝试过的解决方案、为什么
由于使用 main-bower-files 作为使用 Gulp 的编译任务的一部分,我无法使用 node_modules 中的 webpack 来require 模块code> dir 因为我会弄乱当
关闭。这个问题需要更多focused .它目前不接受答案。 想改进这个问题吗? 更新问题,使其只关注一个问题 editing this post . 关闭 5 年前。 Improve this qu
我使用 Gridlayout 在一行中放置 4 个元素。首先,我有一个 JPanel,一切正常。对于行数变大并且我必须能够向下滚动的情况,我对其进行了一些更改。现在我的 JPanel 上添加了一个 J
由于以下原因,我想将 VolumeId 的值保存在变量中: #!/usr/bin/env python import boto3 import json import argparse import
我正在将 MSAL 版本 1.x 更新为 MSAL-browser 的 Angular 。所以我正在尝试从版本 1.x 迁移到 2.X.I 能够成功替换代码并且工作正常。但是我遇到了 acquireT
我知道有很多关于此的问题,例如 Getting daily averages with pandas和 How get monthly mean in pandas using groupby但我遇到
This is the query string that I am receiving in URL. Output url: /demo/analysis/test?startDate=Sat+
我正在尝试使用 javascript 中的以下代码访问 Geoserver 层 var gkvrtWmsSource =new ol.source.ImageWMS({ u
API 需要一个包含授权代码的 header 。这就是我到目前为止所拥有的: var fullUrl = 'https://api.ecobee.com/1/thermostat?json=\{"s
如何获取文件中的最后一个字符,如果是某个字符,则删除它而不将整个文件加载到内存中? 这就是我目前所拥有的。 using (var fileStream = new FileStream("file.t
我是这个社区的新手,想出了我的第一个问题。 我正在使用 JSP,我成功地创建了 JSP-Sites,它正在使用jsp:setParameter 和 jsp:getParameter 具有单个字符串。
在回答 StoreStore reordering happens when compiling C++ for x86 @Peter Cordes 写过 For Acquire/Release se
我有一个函数,我们将其命名为 X1,它返回变量 Y。该函数在操作 .on("focusout", X1) 中使用。如何获取变量Y?执行.on后X1的结果? 最佳答案 您可以更改 Y 的范围以使其位于函
我是一名优秀的程序员,十分优秀!