线程何时会通过条件变量 运行 唤醒?
When will a thread woken via a condition variable run?
当我唤醒一个等待条件变量并持有相应互斥量的线程时,我可以假设被唤醒的线程将 运行 在我释放互斥量之后并且在任何其他人(包括我自己)可以锁定之前又是互斥体?或者我只能确定它会 运行 在未来的某个时候?
准确地说,假设我有以下功能。
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
为假,我能否直接在 enter()
中获取互斥锁(参见代码中的注释)后确定 waiting
必须为零? [在我看来应该是这种情况,因为被唤醒的线程将假设找到唤醒线程已经留下的状态(如果唤醒不是虚假的),否则无法保证,但我做到了在任何地方都找不到明确的措辞。]
我主要对(现代)Linux 上的行为感兴趣,但当然知道这是否由 POSIX 定义也会很感兴趣。
注意:another question中可能已经有人问过这个问题,但我希望我的更清楚。
t0
做pthread_cond_signal
后,t1
不再等待条件变量,但也不是运行ning,因为t0
仍然持有互斥锁; t1
而是在等待互斥量。线程 t2
也可能在 enter()
的开头等待互斥体。现在 t0
释放互斥量。 t1
和 t2
都在等待它。 t1
是以特殊方式处理并保证获得它,还是可以 t2
获得它?
感谢您的评论,卡斯滕,这让事情变得清晰起来。
不,请参阅此 answer 以获取更多参考。鉴于您的示例,t2
可以在 t1
之前获取互斥锁,并且可能会出现竞争条件,从而导致意外结果。
重申,t0
最初可能有互斥锁,并在 while 循环中保持在行 pthread_cond_wait(&c, &m);
上,并且互斥锁被自动释放 reference. t1
could call leave()
acquiring the mutex signaling the condition c
, and then release the mutex. t0
will prepare to run --waiting
by trying to acquire the now-freed mutex by t1
, but it can become context switched by the OS. Some other thread t2
waiting on the mutex can grab it and run enter()
causing undesired outcomes, see non-reentrant。 t2
然后释放互斥锁。 t0
可能会交换回来,只是为了查看值是否发生了变化。
当我唤醒一个等待条件变量并持有相应互斥量的线程时,我可以假设被唤醒的线程将 运行 在我释放互斥量之后并且在任何其他人(包括我自己)可以锁定之前又是互斥体?或者我只能确定它会 运行 在未来的某个时候?
准确地说,假设我有以下功能。
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
为假,我能否直接在 enter()
中获取互斥锁(参见代码中的注释)后确定 waiting
必须为零? [在我看来应该是这种情况,因为被唤醒的线程将假设找到唤醒线程已经留下的状态(如果唤醒不是虚假的),否则无法保证,但我做到了在任何地方都找不到明确的措辞。]
我主要对(现代)Linux 上的行为感兴趣,但当然知道这是否由 POSIX 定义也会很感兴趣。
注意:another question中可能已经有人问过这个问题,但我希望我的更清楚。
t0
做pthread_cond_signal
后,t1
不再等待条件变量,但也不是运行ning,因为t0
仍然持有互斥锁; t1
而是在等待互斥量。线程 t2
也可能在 enter()
的开头等待互斥体。现在 t0
释放互斥量。 t1
和 t2
都在等待它。 t1
是以特殊方式处理并保证获得它,还是可以 t2
获得它?
感谢您的评论,卡斯滕,这让事情变得清晰起来。
不,请参阅此 answer 以获取更多参考。鉴于您的示例,t2
可以在 t1
之前获取互斥锁,并且可能会出现竞争条件,从而导致意外结果。
重申,t0
最初可能有互斥锁,并在 while 循环中保持在行 pthread_cond_wait(&c, &m);
上,并且互斥锁被自动释放 reference. t1
could call leave()
acquiring the mutex signaling the condition c
, and then release the mutex. t0
will prepare to run --waiting
by trying to acquire the now-freed mutex by t1
, but it can become context switched by the OS. Some other thread t2
waiting on the mutex can grab it and run enter()
causing undesired outcomes, see non-reentrant。 t2
然后释放互斥锁。 t0
可能会交换回来,只是为了查看值是否发生了变化。