当我在持有相应互斥锁的同时唤醒等待条件变量的线程时,我是否可以假设唤醒的线程将在我释放互斥锁后运行,并且在其他人(包括我自己)可以再次锁定互斥锁之前运行?或者我只能确定它会在将来的某个时候运行?
准确地说,假设我有以下功能。
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
释放互斥锁。t1
和t2
都在等待它。t1
是以特殊的方式处理并保证得到它,还是t2
可以得到它?
感谢您的评论,卡斯滕,它清除了它。
不,请参阅此答案以获取更多参考。根据您的示例,t2
可以在t1
之前获取互斥锁,并且可能会发生争用条件,从而导致意外结果。
重申一下,t0
最初可能具有互斥锁,并在 while 循环中保持行pthread_cond_wait(&c, &m);
并且互斥锁以原子方式引用释放。t1
可以调用leave()
获取互斥锁,发出条件c
信号,然后释放互斥锁。t0
将准备通过尝试通过t1
获取现已释放的互斥锁来运行--waiting
,但它可以成为操作系统的上下文切换。等待互斥锁的其他一些线程t2
可以获取它并运行enter()
从而导致不希望的结果,请参阅非重入。 然后t2
释放互斥锁。t0
可能交换回来只是为了看到值已经改变。