条件变量wait_untiltimeout_time过去?
Condition Variable wait_until timeout_time in the past?
如果我调用std::condition_variable::wait_until
并传递一个过去的timeout_time
,是否保证return std::cv_status::timeout
?或者是否有一个简短的 window 可以在其中发送通知,导致条件变量以 std::cv_status::no_timeout
的“正常”方式解除阻塞?
上下文:我正在实现一个定时器收集管理器,并打算在条件变量上使用 wait_until
来实现定时器到期。我想要的语义的最简单实现可能涉及将过去的 timeout_time
传递给 std::condition_variable::wait_until
并立即依赖它 returning std::cv_status::timeout
(例如,如果一个计时器在另一个计时器的处理正在进行中)。
请注意,我的标准库 wait_until
的实现遵循 pthread_cond_timedwait
,因此 API 做出的任何保证都适用于这种情况。
TL;DR:(i) std::condition_variable::wait_until()
的 return 值在指定的条件下似乎不受 C++ 的保证,尽管类似的 pthreads 函数确实保证在这些条件下会发出超时信号; (ii) 即使在超时时间已经过去的情况下,该方法的 return 也可以延迟任意时间长度; (iii) 该方法的单次执行可能会消耗信号并报告超时。
更详细:
If I call std::condition_variable::wait_until
and pass a timeout_time
that is in the past, is it guaranteed to return std::cv_status::timeout
?
自从引入 <condition_variable>
以来,所有版本的规范都对 return 值表示基本相同的内容,例如:
Returns: cv_status::timeout
if the absolute timeout (32.2.4) specified by abs_time
expired, otherwise 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()
可能很有启发性。其中:
an error is returned if the absolute
time specified by abstime
passes (that is, system time equals or
exceeds abstime
) before the condition cond is signaled or broadcasted,
or if the absolute time specified by abstime
has already been passed
at the time of the call.
(强调)
因此 pthread_cond_timedwait()
肯定会 return 发出超时信号的错误,如果在调用该函数时超时时间已经过去,并且 wait_until()
实现会决定该超时根据是否 return cv_status::timeout
会表现类似。
而且,pthread_cond_timedwait()
的成功完成并不意味着到函数 returns 时超时还没有过期,即使函数可以做出这样的保证,线程调用该函数不能安全地假设超时不会在函数 returning 和对其 return 值的测试评估之间到期。
另外请注意附加条款:
When such timeouts occur,
pthread_cond_timedwait()
shall nonetheless release and re-acquire the
mutex referenced by mutex, and may consume a condition signal directed
concurrently at the condition variable.
这种互斥锁/锁的释放和重新获取也是C++明确规定的。它说 wait_until()
的效果是:
- Atomically calls
lock.unlock()
and blocks on *this
.
- When unblocked, calls
lock.lock()
(possibly blocking on the lock), then returns.
- The function will unblock [... after] expiration of the absolute timeout [...]
(C++20 草案 4849,第 32.6.3/18 段)
因此,wait_until()
无条件释放锁,即使因为超时立即解除阻塞,也必须重新获取锁。这留下了另一个线程在两者之间获取锁的可能性,在这种情况下,另一个线程可以持有锁任意时间,从而延迟 wait_until()
的 return。对于您的实施计划来说,这可能是一个比方法的 return 值的不确定性更严重的问题。
如果我调用std::condition_variable::wait_until
并传递一个过去的timeout_time
,是否保证return std::cv_status::timeout
?或者是否有一个简短的 window 可以在其中发送通知,导致条件变量以 std::cv_status::no_timeout
的“正常”方式解除阻塞?
上下文:我正在实现一个定时器收集管理器,并打算在条件变量上使用 wait_until
来实现定时器到期。我想要的语义的最简单实现可能涉及将过去的 timeout_time
传递给 std::condition_variable::wait_until
并立即依赖它 returning std::cv_status::timeout
(例如,如果一个计时器在另一个计时器的处理正在进行中)。
请注意,我的标准库 wait_until
的实现遵循 pthread_cond_timedwait
,因此 API 做出的任何保证都适用于这种情况。
TL;DR:(i) std::condition_variable::wait_until()
的 return 值在指定的条件下似乎不受 C++ 的保证,尽管类似的 pthreads 函数确实保证在这些条件下会发出超时信号; (ii) 即使在超时时间已经过去的情况下,该方法的 return 也可以延迟任意时间长度; (iii) 该方法的单次执行可能会消耗信号并报告超时。
更详细:
If I call
std::condition_variable::wait_until
and pass atimeout_time
that is in the past, is it guaranteed to returnstd::cv_status::timeout
?
自从引入 <condition_variable>
以来,所有版本的规范都对 return 值表示基本相同的内容,例如:
Returns:
cv_status::timeout
if the absolute timeout (32.2.4) specified byabs_time
expired, otherwisecv_status::no_timeout
.
(C++20 草案 4849,第 32.6.3/21 段)
但是,总体规范并未明确定义超时已过期的含义。我倾向于认为在调用时已经过去的超时应该算作“绝对超时 [...]调用方法时的过去,而此方法则没有。我不能排除是故意遗漏的。
由于您标记了 pthreads
,<condition_variable>
API 的设计受到这些规范的强烈影响,<condition_variable>
的 UNIX 实现通常涉及薄包装pthreads 函数,考虑 the specifications for pthread_cond_timedwait()
可能很有启发性。其中:
an error is returned if the absolute time specified by
abstime
passes (that is, system time equals or exceedsabstime
) before the condition cond is signaled or broadcasted, or if the absolute time specified byabstime
has already been passed at the time of the call.
(强调)
因此 pthread_cond_timedwait()
肯定会 return 发出超时信号的错误,如果在调用该函数时超时时间已经过去,并且 wait_until()
实现会决定该超时根据是否 return cv_status::timeout
会表现类似。
而且,pthread_cond_timedwait()
的成功完成并不意味着到函数 returns 时超时还没有过期,即使函数可以做出这样的保证,线程调用该函数不能安全地假设超时不会在函数 returning 和对其 return 值的测试评估之间到期。
另外请注意附加条款:
When such timeouts occur,
pthread_cond_timedwait()
shall nonetheless release and re-acquire the mutex referenced by mutex, and may consume a condition signal directed concurrently at the condition variable.
这种互斥锁/锁的释放和重新获取也是C++明确规定的。它说 wait_until()
的效果是:
- Atomically calls
lock.unlock()
and blocks on*this
.- When unblocked, calls
lock.lock()
(possibly blocking on the lock), then returns.- The function will unblock [... after] expiration of the absolute timeout [...]
(C++20 草案 4849,第 32.6.3/18 段)
因此,wait_until()
无条件释放锁,即使因为超时立即解除阻塞,也必须重新获取锁。这留下了另一个线程在两者之间获取锁的可能性,在这种情况下,另一个线程可以持有锁任意时间,从而延迟 wait_until()
的 return。对于您的实施计划来说,这可能是一个比方法的 return 值的不确定性更严重的问题。