重生之我学操作系统——第30章 条件变量
- park()可以让调用线程休眠
- unpark(tid)可以唤醒tid标识的线程
- setpark()可以使线程从park直接返回(其他线程调用unpark后)
- Linux系统里提供futex实现类似机制
为什么我们需要条件变量
void* child(void* arg){
printf("child\n");
// XXX how to indicate we are done?
return NULL;
}
int main(int argc, char* argv[]){
printf("parent: begin\n");
pthread_t c;
pthread_create(&c, NULL, child, NULL); // create child
// xxx how to wait for child?
printf("parent: end\n");
return 0;
}
一种低效的实现
volatile int done = 0;
void* child(void* arg){
printf("child\n");
done = 1;
return NULL;
}
int main(int argc, char* argv[]){
printf("parent: begin\n");
pthread_t c;
pthread_create(&c, NULL, child, NULL); // create child
while(done == 0)
; // spin
printf("parent: end\n");
return 0;
}
目的:判断A是否执行完,A执行完后B才能执行
有什么优化方案?
尝试:引入条件变量
存在问题:线程2执行完第一行后,时间片耗尽,转而先执行线程1的unpark(此时没有休眠线程可以释放),回到线程2后park进入休眠无法释放。
一个简单规则:发送信号时记得加锁
问题:执行线程2的park后,锁没有unlock,陷入死锁
问题:线程2执行完第4行unlock后,可能时间片耗尽跳转到线程1先执行unpark(此时没有休眠线程可以释放),回到线程2后park进入休眠无法释放。
条件变量类型:抽象
事件类型:抽象
- 条件变量
- 是一个显示队列,根据某些特定条件(condition)决定线程行为
- 等待条件:当条件不满足时,线程加入队列(休眠)
- 发出信号:对于其他线程,当改变状态(使条件满足时),可以在队列中唤醒线程
“条件变量”小结
- 条件变量可以处理线程的等待和唤醒
- 在条件变量上等待的线程,会在休眠前解锁,被唤醒后立刻加锁
- 通过条件变量可以实现事件类型,描述事件发生与否
- 如何用条件变量解决实际问题?