条件变量wait_until timeout_time过去了?

Posted

技术标签:

【中文标题】条件变量wait_until timeout_time过去了?【英文标题】:Condition Variable wait_until timeout_time in the past? 【发布时间】:2022-01-19 07:46:01 【问题描述】:

如果我调用std::condition_variable::wait_until 并传递过去的timeout_time,是否保证返回std::cv_status::timeout?或者是否有一个短窗口可以发送通知,导致条件变量以“正常”方式通过std::cv_status::no_timeout 解除阻塞?

上下文:我正在实现一个计时器收集管理器,并打算在条件变量上使用wait_until 来实现计时器到期。我想要的语义的最简单实现可能涉及将过去的timeout_time 传递给std::condition_variable::wait_until 并依赖它立即返回std::cv_status::timeout(例如,如果一个计时器到期而另一个计时器的处理正在进行中)。

请注意,我的 stdlib 对 wait_until 的实现遵循 pthread_cond_timedwait,因此该 API 做出的任何保证都适用于这种情况。

【问题讨论】:

【参考方案1】:

TL;DR:(i) 在指定的条件下,C++ 似乎无法保证 std::condition_variable::wait_until() 的返回值,尽管类似的 pthreads 函数确实保证会发出超时信号在这些条件下; (ii) 即使在超时时间已经过去的情况下,方法的返回也可以延迟任意时间长度; (iii) 方法的单次执行可能会消耗信号并报告超时。

更详细的

如果我调用std::condition_variable::wait_until 并传递过去的timeout_time,是否保证返回std::cv_status::timeout

自从<condition_variable> 引入以来,所有版本的规范都对返回值说了大致相同的事情,例如:

返回:如果abs_time 指定的绝对超时(32.2.4)过期,则cv_status::timeout,否则cv_status::no_timeout

(C++20 草案 4849,第 32.6.3/21 段)

但是,总体规范并未明确定义超时过期的含义。我倾向于认为在调用时已经过去的超时应该算作“绝对超时 [...] 已过期”,但许多其他方法的规范明确解决了绝对超时已经存在时的行为调用该方法时的过去,而该方法没有。我不能排除这种遗漏是故意的。

由于您已标记pthreads<condition_variable> API 的设计受到这些规范的强烈影响,并且<condition_variable> 的 UNIX 实现通常涉及 pthreads 函数的薄包装,考虑the specifications for pthread_cond_timedwait() 可能会很有启发性.其中:

如果绝对值返回错误 abstime 指定的时间通过(即系统时间等于或 超过abstime) 在条件 cond 发出信号或广播之前, 或者如果abstime指定的绝对时间已经过去 在通话时

(已添加重点)

因此,pthread_cond_timedwait() 肯定会返回一个错误信号,如果在调用该函数时超时时间已经过去,那么在此基础上决定是否返回 cv_status::timeoutwait_until() 实现将表现类似.

而且,pthread_cond_timedwait() 的成功完成并不意味着在函数返回时超时尚未到期,即使函数可以做出这样的保证,调用该函数的线程也不能安全地假设timeout 在函数返回和对其返回值的测试评估之间不会过期。

请注意附加条款:

当发生此类超时时, pthread_cond_timedwait() 仍应释放并重新获得 由互斥量引用的互斥量,并且可能会消耗指向的条件信号 同时在条件变量处。

这种互斥锁/锁的释放和重新获取也是由 C++ 明确指定的。它说wait_until()的效果是:

以原子方式调用lock.unlock() 并阻止*this。 解除阻塞时,调用lock.lock()(可能在锁上阻塞),然后返回。 该函数将在绝对超时[...]到期后[...]解除阻塞[...]

(C++20 草案 4849,第 32.6.3/18 段)

因此,wait_until() 无条件释放锁,即使它由于超时而立即解除阻塞,它也必须重新获得锁。这留下了另一个线程在两者之间获取锁的可能性,在这种情况下,其他线程可以将锁持有任意时间,从而延迟wait_until() 的返回。对于您的实施计划而言,这可能是比方法返回值的不确定性更严重的问题。

【讨论】:

谢谢!这很有帮助。我们已经在遵循最小化锁定时间的最佳实践(在我们的例子中是两个向量的交换),所以我不太担心延迟返回。

以上是关于条件变量wait_until timeout_time过去了?的主要内容,如果未能解决你的问题,请参考以下文章

pthread_cond_wait虚假唤醒

XSLT 中的条件变量选择

PHP 会话变量使用条件语句反转值

没有保持锁的条件变量上的信号

如何有条件地在 vue.js 中添加属性?

python简单流程控制