Appearance
进程锁定
与每个进程关联的锁(p->lock
)是xv6中最复杂的锁。一种简单的思考p->lock
的方式是,在读取或写入以下任何struct proc
字段时必须持有它:p->state
、p->chan
、p->killed
、p->xstate
和p->pid
。这些字段可以被其他进程或其他CPU上的调度器线程使用,所以它们必须由一个锁来保护是很自然的。
然而,p->lock
的大多数用途是保护xv6进程数据结构和算法的更高级别的方面。以下是p->lock
所做的全部事情:
- 与
p->state
一起,它防止了为新进程分配proc[]
槽位时的竞争。 - 它在进程创建或销毁时将其隐藏起来。
- 它防止父进程的
wait
收集一个已经将其状态设置为ZOMBIE
但尚未让出CPU的进程。 - 它防止另一个CPU的调度器在让出进程将其状态设置为
RUNNABLE
之后但在完成swtch
之前决定运行它。 - 它确保只有一个CPU的调度器决定运行一个
RUNNABLE
的进程。 - 它防止定时器中断导致进程在
swtch
中让出。 - 与条件锁一起,它有助于防止
wakeup
忽略一个正在调用sleep
但尚未完成让出CPU的进程。 - 它防止
kill
的受害者进程在kill
检查p->pid
和设置p->killed
之间退出并可能被重新分配。 - 它使
kill
对p->state
的检查和写入成为原子操作。
p->parent
字段由全局锁wait_lock
而不是p->lock
保护。只有一个进程的父进程会修改p->parent
,尽管该字段由进程本身和其他正在寻找其子进程的进程读取。wait_lock
的目的是当wait
休眠等待任何子进程退出时充当条件锁。一个正在退出的子进程持有wait_lock
或p->lock
直到它将其状态设置为ZOMBIE
,唤醒其父进程,并让出CPU。wait_lock
还序列化了父进程和子进程并发的exit
,以便init
进程(继承了子进程)保证从其wait
中被唤醒。wait_lock
是一个全局锁而不是每个父进程的锁,因为,在一个进程获取它之前,它无法知道它的父进程是谁。