- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
The POSIX documentation (IEEE 1003.1, 2013) 对于 pthread_cond_timedwait
函数说:
It is important to note that when pthread_cond_wait() and pthread_cond_timedwait() return without error, the associated predicate may still be false. Similarly, when pthread_cond_timedwait() returns with the timeout error, the associated predicate may be true due to an unavoidable race between the expiration of the timeout and the predicate state change.
(强调我的)
我们都知道条件变量控制的谓词应该在 while 循环中检查,并且可能会出现虚假唤醒。但我的问题是关于unavoidable 这个词——这是一个强词。为什么这样的竞赛不可避免?
注意,如果不存在这样的竞争,我们可以只检查 pthread_cond_timedwait 是否超时;而不是再次检查谓词,然后才处理超时条件。 (当然,假设我们仅在 1) 持有互斥量和 2) 谓词实际更改时收到信号。)
在保持“用户互斥量”的情况下,如果我们被超时唤醒或收到信号,是否足以自动检查?
例如,让我们考虑在 POSIX 变量之上构建的条件变量的实现。 (省略了错误处理和初始化,可以填补明显的空白)。
class CV
{
pthread_mutex_t mtx;
pthread_cond_t cv;
int waiters; // how many threads are sleeping
int wakeups; // how many times this cv got signalled
public:
CV();
~CV();
// returns false if it timed out, true otherwise
bool wait(Mutex *userMutex, struct timespec *timeout)
{
pthread_mutex_lock(&mtx);
waiters++;
const int oldWakeups = wakeups;
userMutex->unlock();
int ret; // 0 on success, non-0 on timeout
for (;;) {
ret = pthread_cond_timedwait(&mtx, &cv, timeout);
if (!(ret == 0 && wakeups == 0))
break; // not spurious
}
if (ret == 0) // not timed out
wakeups--;
pthread_mutex_unlock(&mtx);
userMutex->lock();
pthread_mutex_lock(&mtx);
waiters--;
if (ret != 0 && wakeups > oldWakeups) {
// got a wakeup after a timeout: report the wake instead
ret = 0;
wakeups--;
}
pthread_mutex_unlock(&mtx);
return (ret == 0);
}
void wake()
{
pthread_mutex_lock(&mtx);
wakeups = min(wakeups + 1, waiters);
pthread_cond_signal(&cv);
pthread_mutex_unlock(&mtx);
}
};
可以证明
CV::wait
报告超时,那么我们没有收到信号,因此谓词没有改变;还有那个上面的代码是否包含一些严重的错误?如果不是,说这场比赛是不可避免的标准是错误的,还是它必须做一些我错过的其他假设?
最佳答案
首先,请注意这有一个通常很危险的部分:
pthread_mutex_unlock(&mtx);
// Trouble is here
userMutex->lock();
pthread_mutex_lock(&mtx);
在注释点,任何事情都有可能发生。你没有锁。条件变量的强大之处在于它们总是要么持有锁,要么等待。
然后是手头的问题,不可避免的比赛
if (ret != 0 && wakeups > oldWakeups) {
// got a wakeup after a timeout: report the wake instead
ret = 0;
wakeups--;
}
无法保证一堆 pthread_cond_t 的等待会以何种顺序被唤醒,这会对您的计数造成严重破坏
Thread1 Thread2 Thread3
{lock userMtx in calling code}
{lock mtx}
waiters++ (=1)
oldWakeups = 0
{unlock userMtx }
wait {unlock mtx}
{lock userMtx in calling code}
{lock mtx}
signal_all
wakeups = 1
{unlock mtx}
{unlock userMtx in calling code}
timeout(unavoid. racecase) {lock mtx}
{unlock mtx}
{lock userMtx in calling code}
{lock mtx}
waiters++ (=2)
oldWawkupes = 1
{unlock userMtx }
wait {unlock mtx}
timeout {lock mtx}
{unlock mtx}
{lock userMtx}
{lock mtx}
waiters-- (=1)
wakeups-- (=0)*
{unlock mtx}
{unlock userMtx in calling code}
{lock userMtx}
{lock mtx}
waiters--(=0)
wakeups == oldWakeups (=0)
{unlock mtx}
{unlock userMtx in calling code}
此时,在线程 1 上,oldWakeups = wakeups,因此对不可避免的竞争情况的检查未能注意到竞争情况,从而重新创建了不可避免的竞争情况。这是由于线程 3 窃取了线程 1 的信号,使线程 3(真正的超时)看起来像一个信号,而线程 1(竞争信号/超时)看起来像一个超时
关于c++ - 为什么 pthread_cond_timedwait 文档谈论 "unavoidable race"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18642385/
The POSIX documentation (IEEE 1003.1, 2013) 对于 pthread_cond_timedwait 函数说: It is important to note t
在“错误/警告”面板中设置 Java 编译器的首选项时,Eclipse 可以配置为“忽略不可避免的泛型类型问题”。 Java 中这种“不可避免”的泛型类型问题是什么?忽略这些安全吗?它们什么时候出现?
动机 C++ 核心指南推荐使用 dynamic_cast当“类层次结构导航是不可避免的”时。这会触发 clang-tidy 抛出以下错误:Do not use static_cast to downc
我是一名优秀的程序员,十分优秀!