当我唤醒一个等待条件变量并持有相应互斥锁的线程时,我是否可以假设被唤醒的线程将在我释放互斥锁之后并且在其他任何人(包括我自己)可以再次锁定互斥锁之前运行?或者我只能确定它会在未来的某个时间点运行吗?
准确地说,假设我有以下功能。
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()
如果 taken
为 false waiting
必须为零? [在我看来应该是这种情况,因为被唤醒的线程将假设找到唤醒线程已经留下的状态(如果唤醒不是虚假的),否则无法保证,但我做到了在任何地方都找不到它的明确措辞。]
我主要对(现代)Linux 上的行为感兴趣,但当然知道这是否由 POSIX 定义也很感兴趣。
注意:这可能已经在 another question 中提出过, 但我希望我的更清楚。
t0
做完pthread_cond_signal
后,t1
不再等待条件变量,但也没有运行,因为 t0
仍然持有互斥锁; t1
而是等待互斥量。线程 t2
也可能在 enter()
开始时等待互斥锁。现在 t0
释放互斥体。 t1
和 t2
都在等待它。 t1
是否以特殊方式处理并保证获取它,或者 t2
是否可以获取它?
最佳答案
感谢您的评论,Carsten,这澄清了一切。
不,请参阅此 answer 以获取更多引用。在您的示例中,t2
可能会在 t1
之前获取互斥锁,并且可能会出现竞争条件,从而导致意外结果。
重申,t0
最初可能有互斥锁,并且在 while 循环中保持在 pthread_cond_wait(&c, &m);
行上,并且互斥锁以原子方式释放 reference 。 t1
可以调用 leave()
获取互斥信号条件 c
,然后释放互斥信号。 t0
将尝试通过 t1
获取现在释放的互斥锁来准备运行 --waiting
,但它可以成为操作系统切换的上下文.等待互斥锁的一些其他线程 t2
可以获取它并运行 enter()
导致意外结果,请参阅 non-reentrant 。 t2
然后释放互斥体。 t0
可能会交换回来,只是为了查看值是否发生了变化。
关于c - 通过条件变量唤醒的线程何时运行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44417242/