c - 线程何时通过条件变量运行唤醒?



当我在持有相应互斥锁的同时唤醒等待条件变量的线程时,我是否可以假设唤醒的线程将在我释放互斥锁后运行,并且在其他人(包括我自己)可以再次锁定互斥锁之前运行?或者我只能确定它会在将来的某个时候运行?

准确地说,假设我有以下功能。

bool taken = false;
int waiting = 0;
pthread_mutex_t m;   // properly initialised elsewhere
pthread_cond_t c;
void enter() {
pthread_mutex_lock(&m);
// Is `taken || (waiting == 0)` guaranteed here? 
while (taken) {
++ waiting;
pthread_cond_wait(&c, &m);
-- waiting;
}
taken = true;
pthread_mutex_unlock(&m);
}
void leave() {
pthread_mutex_lock(&m);
taken = false;
if (waiting > 0) {
pthread_cond_signal(&c);
}
pthread_mutex_unlock(&m);
}

(这是一个玩具示例,没有用处。

还假设所有线程都使用这些函数作为

enter()
// some work here
leave()

然后,我是否可以确定在获取enter()中的互斥锁后(请参阅代码中的注释),如果taken为假waiting则必须为零?[在我看来应该是这种情况,因为唤醒的线程会假设找到唤醒线程留下的状态(如果唤醒不是虚假的),否则无法保证这一点,但我没有发现它在任何地方都写得很清楚。

我主要对(现代)Linux上的行为感兴趣,但当然知道这是否由POSIX定义也会感兴趣。

注意:这可能已经在另一个问题中问过了,但我希望我的问题更清楚。


t0执行pthread_cond_signal后,t1不再等待条件变量,但它也没有运行,因为t0仍然持有互斥锁;t1正在等待互斥锁。线程t2也可能在enter()开始时等待互斥锁。现在t0释放互斥锁。t1t2都在等待它。t1是以特殊的方式处理并保证得到它,还是t2可以得到它?

感谢您的评论,卡斯滕,它清除了它。

不,请参阅此答案以获取更多参考。根据您的示例,t2可以在t1之前获取互斥锁,并且可能会发生争用条件,从而导致意外结果。

重申一下,t0最初可能具有互斥锁,并在 while 循环中保持行pthread_cond_wait(&c, &m);并且互斥锁以原子方式引用释放。t1可以调用leave()获取互斥锁,发出条件c信号,然后释放互斥锁。t0将准备通过尝试通过t1获取现已释放的互斥锁来运行--waiting,但它可以成为操作系统的上下文切换。等待互斥锁的其他一些线程t2可以获取它并运行enter()从而导致不希望的结果,请参阅非重入。 然后t2释放互斥锁。t0可能交换回来只是为了看到值已经改变。

最新更新