- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
在下面的选项中,有没有正确的方法来处理使用条件变量时的虚假唤醒?
1) 使用 bool 值将 wait(unique_lock_ul)
放入无限的 while
循环中
unique_lock<mutex> ul(m);
while(!full)
cv.wait(ul);
2) 与 if 相同
unique_lock<mutex> ul(m);
if(!full)
cv.wait(ul);
3) 在 wait()
中放置一个条件,例如使用 lambda 函数
unique_lock<mutex> ul(m);
cv.wait(ul, [&](){return !full;});
如果这些都不正确,如何轻松应对虚假唤醒?
我对 C++ 中的条件变量相当陌生,我不确定我阅读的某些代码是否处理虚假唤醒的情况。
最佳答案
简短的回答是,您的代码可能正确也可能错误;您没有确切说明 full
是如何被操纵的。
C++ 代码的个别位永远不是线程安全的。线程安全是代码的关系属性;如果两位代码永远不会导致竞争条件,那么它们就可以是线程安全的。
但是一点代码永远都不是线程安全的;说某物是线程安全的就像说某物是“相同的高度”。
“monkey see monkey do”条件变量模式是这样的:
template<class T>
class cv_bundle {
std::mutex m;
T payload;
std::condition_variable cv;
public:
explicit cv_bundle( T in ):payload(std::move(in)) {}
template<class Test, class Extract>
auto wait( Test&& test, Extract&& extract ) {
std::unique_lock<std::mutex> l(m);
cv.wait( l, [&]{ return test(payload); } );
return extract(payload);
}
template<class Setter>
void load( Setter&& setter, bool only_one = true ) {
std::unique_lock<std::mutex> l(m);
bool is_set = setter( payload );
if (!is_set) return; // nothing to notify
if (only_one)
cv.notify_one();
else
cv.notify_all();
}
};
test
接受一个 T& payload
并在有东西要消耗时返回 true(即,唤醒不是虚假的)。
extract
获取一个 T& payload
并返回您想要从中获取的任何信息。它通常应该重置有效负载。
setter
以 test
将返回 true
的方式修改 T& payload
。如果这样做,它会返回 true
。如果选择不这样做,则返回 false
。
所有 3 个都在锁定访问 T payload
的互斥锁中被调用。
现在,您可以生成变体,但很难做到正确。例如,不要假设原子负载意味着您不必锁定互斥量。
虽然我将这 3 个东西捆绑在一起,但您可以对一堆条件变量使用单个互斥锁,或者将互斥锁用于条件变量之外的其他对象。有效载荷可以是一个 bool 值、一个计数器、一个数据 vector ,或者更奇怪的东西;通常,它必须始终受到互斥锁的保护。如果它是原子的,则在被修改的值和通知之间的开放时间间隔内的某个时间点,必须锁定互斥体,否则您可能会丢失通知。
手动循环控制而不是传入lambda是一种修改,但是描述什么样的手动循环是合法的,哪些是竞争条件是一个复杂的问题。
实际上,除非我有非常充分的理由,否则我避免离开这种猴子看猴子做的“ cargo 崇拜”风格的条件变量使用。然后我被迫阅读 C++ 内存和线程模型,这让我很不高兴,这意味着我的代码很可能不正确。
请注意,如果传入的任何 lambda 表达式返回并回调到 cv_bundle
,我显示的代码将不再有效。
关于c++ - 一般来说,处理虚假唤醒的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52192203/
我正在阅读雷姆齐教授的OSTEP书 http://pages.cs.wisc.edu/~remzi/OSTEP/ 我只能部分理解以下代码如何导致唤醒/等待竞态条件。(该代码摘自书籍一章。 http:/
我目前正在构建一个应用程序,如果我的 android 手机处于锁定状态,我想在收到任何通知时避免屏幕亮起。 我正在尝试找到解决方案,但我找不到任何方法。 我在 switch.setOnCheckedC
有没有办法以编程方式进入 BIOS 并为支持 LAN 唤醒功能的机器打开该功能? 理想情况下,解决方案应该是跨 BIOS,但使用单独的解决方案来打击每个主要供应商也是可以的。 最佳答案 BIOS 配置
我有大量的 Azure 数据库,目前有 6 个,但随着时间的推移,这个数量将会增加。 数据库的访问频率很低,因此为了节省成本,它们被设置为 1 小时后自动休眠。 我需要在 Access 中连接到一个或
我有一个已纳入消费计划的现有 Azure Function 我正在编写另一个函数来调用它 现有函数运行后,它会处理存储帐户中的文件。 为了处理我的存储帐户中的文件,我们必须手动进入门户并通过导航“唤醒
我有一个已纳入消费计划的现有 Azure Function 我正在编写另一个函数来调用它 现有函数运行后,它会处理存储帐户中的文件。 为了处理我的存储帐户中的文件,我们必须手动进入门户并通过导航“唤醒
我想使用方法 wakeUp电源管理器。Eclipse (ADT) 不调整此方法。但是对面的“goToSleep”就没有问题了: PowerManager pm = (PowerManager) MyA
我有以下线程池。 #include #include #include #include #include #include #include // remove me (only fo
我写了一个Java程序,它分析其他程序。执行可能需要很长时间(=几天)。现在(三天后),我遇到了问题,我的程序/进程正在 sleep (S)。它仍然分配了 50% 的内存,有时会打印新的输出,但 to
我有一个很简单的问题。 我们使用 BackgroundAgents( Periodic agents ) 来执行一些后台任务,这些任务需要 WiFi(Internet) 连接才能执行 HttpWebR
我读了一些其他帖子,但没有找到我正在寻找的确切答案,所以我希望有人能给出一些澄清。 我有一个程序会运行一段时间。我有一些在后台运行的线程来执行各种任务,为了简单起见,让我们想想 3 个线程。 Thre
我的后台服务正在尽快将消息发送到本地服务器。每条消息通常需要大约 30 毫秒。但是,当手机处于 sleep 模式时,大约需要 400 毫秒到 1000 毫秒(使用“正确”的 Wifi 策略关闭屏幕)
嘿,我需要在某个时间唤醒我正在 sleep 的 Android 设备。有什么建议吗? 附:唤醒:打开显示屏并可能解锁手机 最佳答案 唤醒屏幕: PowerManager pm = (PowerMana
我们有一个用 C# 编写的 Windows 服务。该服务会生成一个执行此操作的线程: private void ThreadWorkerFunction() { while(false == _s
在scala中,我如何告诉线程: sleep t秒钟,或直到收到消息?也就是说,最多只能睡t秒钟,但是如果t尚未结束,您会醒来,并且您会收到一条特定的消息。 最佳答案 或者,您可以使用条件变量。 va
我发现我们可以在 Awake() 或 Start() 中初始化变量,并且 Awake() 将在 之前调用开始()。 我们应该什么时候在Awake和Start中进行初始化才能获得最佳性能? 最佳答案 通
在 Windows Azure 辅助角色中处理“紧急”消息的最佳方式是什么? 我有一个启动的辅助角色,执行无限 while(true) 循环,并在此循环中: 读取队列中是否有消息 处理它们并删除它们
你好,我已经调试了我的代码一整天,但我就是看不出哪里可能出错。 我在主线程上使用 SerialPortEventListener,在工作线程中我有一个与服务器通信的客户端套接字。由于此工作线程到达re
我想知道线程何时从某个条件中唤醒我在消费者线程上有这样的东西 while(true) { std::unique_lock gu
我希望这个问题适合 SE,但如果不适合,请告诉我可以将其移动到哪里,我会很乐意这样做。我目前正在构建一个 iOS 应用程序,需要在发出“匹配预订请求”时唤醒设备/中断当前应用程序,我正在寻找的行为类似
我是一名优秀的程序员,十分优秀!