条件变量的问题&参考回答

Q1: Why need while() instead of if() when calling pthread_cond_wait()

A1: 因为可能会导致假唤醒(spurious wakeup)。设想一种情景,比如生产者消费者问题,有多个消费线程在等待,当一个消费者(C1)将被唤醒时,此时另外一个消费者(C2)可能抢占(preempt)这个信号,而C2很可能消费了C1应消费的,从而导致C1可能出现UB行为(比如assert保证此时有资源可供消费),这种情景应该继续sleep,用while进行多次判断从而避免单次判断带来的假唤醒。

Q2: Why need mutex when calling pthead_cond_signal/wait()

A2: 共享不强制要求互斥,但互斥需求是常有的,条件变量也不例外,其关联的变量往往也有互斥需求,需要保证其操作是原子的。设想如下情景:
当调用wait()要sleep时,突然中断或异常发生,上下文切换到其他线程,并且调用signal(),然后再切换回原来的线程,那么这个线程很可能就没有其他线程可以唤醒了,这种现象称为“丢失唤醒”。
因此为了避免出现“丢失唤醒”,我们应该用mutex等满足互斥需求的同步原语同步线程的行为。

Q3: Is is necessary to lock when calling wait()

A3: 从A2来看,是很有必要的,否则可能出现“丢失唤醒”。

Q4: Is is necessary to lock when calling signal()

A4: 对于timedwait()来说不是必要的,但终究是非常规用法。对于一般的wait()还是必须得加锁,不能在临界区外面调用signal()。设想如下情景:

1
2
3
4
mutex.lock();
increment_condition_variable(); // increment the variable related to condition instead condition itself
mutex.unlock(); // FIXME use MutexGuard
cond.signal();

还是生产者消费者问题:在unlock()与signal()间,上下文切换到消费者线程,由于signal()没有被锁住,所以它可能会在消费者线程调用wait()前就被调用,从而导致出现“丢失唤醒”。

Q5: The semantic of signal()/broadcast()

API semantic
signal resource availability
broadcast state change