- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我研究了 std::condition_variable(lock,pred)
的 VC++ 实现,基本上,它看起来像这样:
template<class _Predicate>
void wait(unique_lock<mutex>& _Lck, _Predicate _Pred)
{ // wait for signal and test predicate
while (!_Pred())
wait(_Lck);
}
基本上,裸 wait
调用 _Cnd_waitX
,它调用 _Cnd_wait
,它调用 do_wait
,它调用 cond ->_get_cv()->wait(cs);
(所有这些都在文件 cond.c 中)。
cond->_get_cv()
返回 Concurrency::details::STL_condition_variable_interface
。
如果我们转到文件 primitives.h
,我们会看到在 Windows 7 及更高版本下,我们有类 STL_condition_variable_win7
,其中包含旧的好 win32 CONDITION_VARIABLE
,并且 wait
调用 __crtSleepConditionVariableSRW
。
做一些汇编调试,__crtSleepConditionVariableSRW
只是提取 SleepConditionVariableSRW
函数指针,并调用它。
事情是这样的:据我所知,win32 CONDITION_VARIABLE
不是内核对象,而是用户模式对象。因此,如果某个线程通知了这个变量,但实际上没有线程在它上面休眠,那么你就失去了通知,线程将保持休眠状态,直到超时或其他线程通知它。一个小程序实际上可以证明这一点——如果你错过了通知点——你的线程将继续休眠,尽管其他线程通知了它。
我的问题是这样的:
一个线程等待条件变量并且谓词返回 false。然后,发生上面解释的整个调用链。那时,另一个线程改变了环境,因此谓词将返回 true 并 通知条件变量。我们在原始线程中传递了谓词,但我们仍然没有进入 SleepConditionVariableSRW
- 调用链很长。
因此,尽管我们通知了条件变量并且放在条件变量上的谓词肯定会返回 true(因为通知者这样做了),我们仍然阻塞在条件变量上,可能永远阻塞。
这是它的行为方式吗?这似乎是一个巨大的、丑陋的竞争条件等待发生。如果您通知条件变量并且它的谓词返回 true - 线程应该解除阻塞。但是,如果我们在检查谓词和进入休眠之间处于中间状态——我们将永远被阻塞。 std::condition_variable::wait
不是原子函数。
标准是怎么说的?它真的是竞争条件吗?
最佳答案
你违反了契约(Contract),所以所有的赌注都被取消了。请参阅:http://en.cppreference.com/w/cpp/thread/condition_variable
TLDR:当您持有互斥锁时,谓词不可能被其他人更改。
您应该在持有互斥锁的同时更改谓词的基础变量并且您必须在调用std::condition_variable::wait
之前获取该互斥锁。 (既因为 wait
释放了互斥体,也因为那是契约)。
在您描述的场景中,更改发生在 之后 while (!_Pred())
看到谓词不成立但在 wait(_Lck)
之前有机会释放互斥量。这意味着您在不持有互斥体的情况下更改了谓词检查的内容。你违反了规则,竞争条件或无限等待仍然不是你能得到的最糟糕的 UB 类型。至少这些是本地的并且与您违反的规则相关,因此您可以找到错误...
如果您遵守规则,则:
std::condition_variable::wait
. (回想一下,通知程序仍在等待互斥量。)std::condition_variable::notify_one
.或:
std::condition_variable::notify_one
,但是一旦互斥量被释放......)std::condition_variable::wait
.while (!_Pred())
和 viola! 谓词为真。wait
,所以通知者是否成功调用了std::condition_variable::notify_one
或者还没有设法做到这一点是无关紧要的。这就是 cppreference.com 要求背后的基本原理:
Even if the shared variable is atomic, it must be modified under the mutex in order to correctly publish the modification to the waiting thread.
请注意,这是对条件变量的一般规则,而不是对 std::condition_variables
的特殊要求s(包括 Windows CONDITION_VARIABLE
s、POSIX pthread_cond_t
s 等)。
回想一下 wait
采用谓词的重载只是一个方便的函数,因此调用者不必处理虚假唤醒。标准 (§30.5.1/15) 明确指出此重载等同于 Microsoft 实现中的 while 循环:
Effects: Equivalent to:
while (!pred())
wait(lock);
做简单的wait
工作?你在调用wait
之前和之后测试谓词吗? ?伟大的。你也在做同样的事情。或者你在质疑void std::condition_variable::wait( std::unique_lock<std::mutex>& lock );
也是吗?
Windows Critical Sections 和 Slim Reader/Writer Locks 是用户模式设施而不是内核对象,这与问题无关紧要。有替代的实现。如果您有兴趣了解 Windows 如何设法以原子方式释放 CS/SRWL 并进入等待状态(使用互斥锁和事件的天真的 pre-Vista 用户模式实现做错了什么),那是另一个问题。
关于c++ - std::condition_variable 中可能的竞争条件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42470773/
这很可能是我的语法错误,因为我对在 C++ 中使用多个文件和结构(特别是将结构传递给函数)还很陌生。这是三个文件: 主要.cpp: #include #include #include #inc
我有 TypeScript NestJS 项目。 我需要验证传入的 DTO 到我的 API。它可以被描述为“创建项目”,其中我们有建筑类型(房屋、公寓、花园),并根据该类型我们需要定义: 房屋:楼层包
是否可以从可用于泛型参数的可能类型集中排除特定类型?如果是如何。 例如 Foo() : where T != bool 将意味着除了类型 bool 之外的任何类型。 编辑 为什么? 以下代码是我尝试强
我的 WebGL 体积光线转换应用程序即将完成。但是我发现了一个问题。我必须通过 2D 纹理模拟 3D 纹理。这不是问题。我正在用小切片创建一个巨大的纹理。巨大纹理的尺寸约为 4096x4096 像素
我正在处理的网页上显示了一个返回顶部按钮。当您向下滚动时,有时单击它时,它会跳到顶部,然后跳回您在页面上的位置,然后像预期的那样平滑滚动到顶部。请记住,它并不总是这样做。这只是一个滞后或故障问题还是我
我对此还很陌生,所以请耐心等待。 我有一个类,它具有三个属性:几个整数和一个用户定义对象的集合。 public class Response { public int num1 { get;
我正在制作一款平台游戏,让玩家每 30 毫秒跳跃一次,并向上添加少量的力。我想我应该使用多线程,因为我之前已经做过一些,而且看起来很简单。无论如何,我尝试了这个: public void jump()
是否可以从可能的类型集中排除特定类型,这些类型可以在泛型参数中使用?如果是这样的话。 例如 Foo() : where T != bool 表示除 bool 类型之外的任何类型。 编辑 为什么? 以下
我正在尝试在单个查询中实现内部和外部联接,我不确定我的做法是正确还是错误,因为我不太擅长查询。 就这样吧。 我有以下表格。 hrs_residentials hrs_residential_utili
关于 my website ,有一段代码可以向页面添加几个元素。这段代码不是我可以编辑的东西,而且我对它放置这些元素的位置不满意,因为它弄乱了我的一些布局。所以我想出了一个小的 jQuery 来将它们
一位客户希望我创建一个数据集,如下所示。我不知道这是否可能或合乎逻辑。 我有表parent: id name ------- ------- 1 parent1 2
这可能吗?google 好像没有这方面的资料.. 这样,如果用户在另一个网站上播放视频或歌曲,我的音量就会自动减小 最佳答案 不,这是不可能的。 如果可能的话,它必须是特定于浏览器的,但我不认为这种情
所以我正在尝试制作响应式页面。问题是为什么它归结为移动数据需要位于列表中。 我会用一些示例代码来解释 所以这可能是桌面上的输出 option1
当您将鼠标悬停在a 元素 上时,是否可以删除url? 这就是我的意思: 最佳答案 一种选择是使用一些 JavaScript。 删除 href=来自 的属性标签,取而代之的是 onclick=...
我已经考虑了几个小时,但我无法取得太大进展。它是这样的: You have an array of size n and q queries. Each query is of the form (l
我一直在尝试编写一个脚本来强化 android。我没有成功! 我正在通过模拟器运行一个 AVD,并且已经用我加载的 android shell 和 bash shell 试过了。正如您将在下面看到的那
Private Sub Workbook_Open() Dim WBname As String WBname = ThisWorkbook.name If Not InStr(WBname, "te
Spark 2.0.0-预览版 我们有一个应用程序使用了相当大的广播变量。我们在大型 EC2 实例上运行它,因此部署处于客户端模式。广播变量是一个巨大的 Map[String, Array[Strin
我正在尝试从此link中提取摘要。但是,我无法仅提取摘要的内容。到目前为止,这是我完成的工作: url <- "http://www.scielo.br/scielo.php?script=sci_a
我的主页中有一个iframe。 iframe页面中有一个modalpopup。因此,当显示modalpopup时,modalpopup的父级是iframe主体和主页父级主体。因此,覆盖层仅覆盖ifra
我是一名优秀的程序员,十分优秀!