Skip to content

Commit

Permalink
GitBook: [master] 24 pages and 89 assets modified
Browse files Browse the repository at this point in the history
  • Loading branch information
huihongxiao authored and gitbook-bot committed Jan 19, 2021
1 parent ecb2e95 commit 3e81918
Show file tree
Hide file tree
Showing 113 changed files with 125 additions and 75 deletions.
Binary file modified .gitbook/assets/image (485).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .gitbook/assets/image (486).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .gitbook/assets/image (487).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .gitbook/assets/image (488).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .gitbook/assets/image (489).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .gitbook/assets/image (490).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .gitbook/assets/image (491).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .gitbook/assets/image (492).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .gitbook/assets/image (493).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .gitbook/assets/image (496).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .gitbook/assets/image (498).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .gitbook/assets/image (499).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .gitbook/assets/image (500).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .gitbook/assets/image (502).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .gitbook/assets/image (503).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .gitbook/assets/image (504).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .gitbook/assets/image (506).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .gitbook/assets/image (507).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .gitbook/assets/image (508).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .gitbook/assets/image (509).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .gitbook/assets/image (511).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .gitbook/assets/image (512).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .gitbook/assets/image (513).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .gitbook/assets/image (514).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .gitbook/assets/image (517).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified .gitbook/assets/image (518).png
Binary file modified .gitbook/assets/image (519).png
Binary file modified .gitbook/assets/image (520).png
Binary file modified .gitbook/assets/image (521).png
Binary file modified .gitbook/assets/image (522).png
Binary file modified .gitbook/assets/image (523).png
Binary file modified .gitbook/assets/image (525).png
Binary file modified .gitbook/assets/image (526).png
Binary file modified .gitbook/assets/image (527).png
Binary file modified .gitbook/assets/image (528).png
Binary file modified .gitbook/assets/image (529).png
Binary file modified .gitbook/assets/image (530).png
Binary file modified .gitbook/assets/image (531).png
Binary file modified .gitbook/assets/image (532).png
Binary file modified .gitbook/assets/image (533).png
Binary file modified .gitbook/assets/image (534).png
Binary file modified .gitbook/assets/image (535).png
Binary file modified .gitbook/assets/image (536).png
Binary file modified .gitbook/assets/image (537).png
Binary file modified .gitbook/assets/image (538).png
Binary file modified .gitbook/assets/image (540).png
Binary file modified .gitbook/assets/image (542).png
Binary file modified .gitbook/assets/image (543).png
Binary file modified .gitbook/assets/image (544).png
Binary file modified .gitbook/assets/image (545).png
Binary file modified .gitbook/assets/image (546).png
Binary file modified .gitbook/assets/image (547).png
Binary file modified .gitbook/assets/image (548).png
Binary file modified .gitbook/assets/image (549).png
Binary file modified .gitbook/assets/image (550).png
Binary file modified .gitbook/assets/image (551).png
Binary file modified .gitbook/assets/image (552).png
Binary file modified .gitbook/assets/image (553).png
Binary file modified .gitbook/assets/image (554).png
Binary file modified .gitbook/assets/image (555).png
Binary file modified .gitbook/assets/image (556).png
Binary file modified .gitbook/assets/image (557).png
Binary file modified .gitbook/assets/image (558).png
Binary file modified .gitbook/assets/image (559).png
Binary file modified .gitbook/assets/image (560).png
Binary file modified .gitbook/assets/image (561).png
Binary file modified .gitbook/assets/image (562).png
Binary file modified .gitbook/assets/image (563).png
Binary file modified .gitbook/assets/image (564).png
Binary file modified .gitbook/assets/image (565).png
Binary file modified .gitbook/assets/image (566).png
Binary file modified .gitbook/assets/image (567).png
Binary file modified .gitbook/assets/image (568).png
Binary file modified .gitbook/assets/image (569).png
Binary file modified .gitbook/assets/image (570).png
Binary file modified .gitbook/assets/image (571).png
Binary file modified .gitbook/assets/image (572).png
Binary file modified .gitbook/assets/image (573).png
Binary file modified .gitbook/assets/image (574).png
Binary file modified .gitbook/assets/image (575).png
Binary file modified .gitbook/assets/image (576).png
Binary file modified .gitbook/assets/image (577).png
Binary file modified .gitbook/assets/image (578).png
Binary file modified .gitbook/assets/image (579).png
Binary file added .gitbook/assets/image (580).png
Binary file added .gitbook/assets/image (581).png
Binary file added .gitbook/assets/image (582).png
Binary file added .gitbook/assets/image (583).png
Binary file added .gitbook/assets/image (584).png
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

首先你们在脑海里应该有多个CPU核在运行,比如说CPU0在运行指令,CPU1也在运行指令,这两个CPU核都连接到同一个内存上。在前面的代码中,数据freelist位于内存中,它里面记录了2个内存page。假设两个CPU核在相同的时间调用kfree。

![](../.gitbook/assets/image%20%28506%29.png)
![](../.gitbook/assets/image%20%28507%29.png)

kfree函数接收一个物理地址pa作为参数,freelist是个单链表,kfree中将pa作为单链表的新的head节点,并更新freelist指向pa(注,也就是将空闲的内存page加在单链表的头部)。当两个CPU都调用kfree时,CPU0想要释放一个page,CPU1也想要释放一个page,现在这两个page都需要加到freelist中。

![](../.gitbook/assets/image%20%28570%29.png)
![](../.gitbook/assets/image%20%28572%29.png)

kfree中首先将对应内存page的变量r指向了当前的freelist(也就是单链表当前的head节点)。我们假设CPU0先运行,那么CPU0会将它的变量r的next指向当前的freelist。如果CPU1在同一时间运行,它可能在CPU0运行第二条指令(kmem.freelist = r)之前运行代码。所以它也会完成相同的事情,它会将自己的变量r的next指向当前的freelist。现在两个物理page对应的变量r都指向了同一个freelist(注,也就是原来单链表的head节点)。

Expand All @@ -23,19 +23,19 @@ kfree中首先将对应内存page的变量r指向了当前的freelist(也就
* acquire,接收指向lock的指针作为参数。acquire确保了在任何时间,只会有一个进程能够成功的获取锁。
* release,也接收指向lock的指针作为参数。在同一时间尝试获取锁的其他进程需要等待,直到持有锁的进程对锁调用release。

![](../.gitbook/assets/image%20%28575%29.png)
![](../.gitbook/assets/image%20%28579%29.png)

锁的acquire和release之间的代码,通常被称为critical section。

![](../.gitbook/assets/image%20%28522%29.png)
![](../.gitbook/assets/image%20%28525%29.png)

之所以被称为critical section,是因为通常会在这里以原子的方式执行共享数据的更新。所以基本上来说,如果在acquire和release之间有多条指令,它们要么会一起执行,要么一条也不会执行。所以永远也不可能看到位于critical section中的代码,如同在race condition中一样在多个CPU上交织的执行,所以这样就能避免race condition。

现在的程序通常会有许多锁。实际上,XV6中就有很多的锁。为什么会有这么多锁呢?因为锁序列化了代码的执行。如果两个处理器想要进入到同一个critical section中,只会有一个能成功进入,另一个处理器会在第一个处理器从critical section中退出之后再进入。所以这里完全没有并行执行。

如果内核中只有一把大锁,我们暂时将之称为big kernel lock。基本上所有的系统调用都会被这把大锁保护而被序列化。系统调用会按照这样的流程处理:一个系统调用获取到了big kernel lock,完成自己的操作,之后释放这个big kernel lock,再返回到用户空间,之后下一个系统调用才能执行。这样的话,如果我们有一个应用程序并行的调用多个系统调用,这些系统调用会串行的执行,因为我们只有一把锁。所以通常来说,例如XV6的操作系统会有多把锁,这样就能获得某种程度的并发执行。如果两个系统调用使用了两把不同的锁,那么它们就能完全的并行运行。

![](../.gitbook/assets/image%20%28571%29.png)
![](../.gitbook/assets/image%20%28573%29.png)

这里有几点很重要,首先,并没有强制说一定要使用锁,锁的使用完全是由程序员决定的。如果你想要一段代码具备原子性,那么其实是由程序员决定是否增加锁的acquire和release。其次,代码不会自动加锁,程序员自己要确定好是否将锁与数据结构关联,并在适当的位置增加锁的acquire和release。

Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

很明显,锁限制了并发性,也限制了性能。那这带来了一个问题,什么时候才必须要加锁呢?我这里会给你们一个非常保守同时也是非常简单的规则:如果两个进程访问了一个共享的数据结构,并且其中一个进程会更新共享的数据结构,那么就需要对于这个共享的数据结构加锁。

![](../.gitbook/assets/image%20%28504%29.png)
![](../.gitbook/assets/image%20%28506%29.png)

这是个保守的规则,如果一个数据结构可以被多个进程访问,其中一个进程会更新这个数据,那么可能会产生race condition,应该使用锁来确保race condition不会发生。

Expand All @@ -28,15 +28,15 @@

如果我们按照前面说的,对数据结构自动加锁。现在我们有两个目录对象,一个是d1,另一个是d2,那么我们会先对d1加锁,删除x,之后再释放对于d1的锁;之后我们会对d2加锁,增加y,之后再释放d2的锁。这是我们在使用自动加锁之后的一个假设的场景。

![](../.gitbook/assets/image%20%28487%29.png)
![](../.gitbook/assets/image%20%28488%29.png)

在这个例子中,我们会有错误的结果,那么为什么这是一个有问题的场景呢?为什么这个场景不能正常工作?

在我们完成了第一步,也就是删除了d1下的x文件,但是还没有执行第二步,也就是创建d2下的y文件时。其他的进程会看到什么样的结果?是的,其他的进程会看到文件完全不存在。这明显是个错误的结果,因为文件还存在只是被重命名了,文件在任何一个时间点都是应该存在的。但是如果我们按照上面的方式实现锁的话,那么在某个时间点,文件看起来就是不存在的。

所以这里正确的解决方法是,我们在重命名的一开始就对d1和d2加锁,之后删除x再添加y,最后再释放对于d1和d2的锁。

![](../.gitbook/assets/image%20%28488%29.png)
![](../.gitbook/assets/image%20%28489%29.png)

在这个例子中,我们的操作需要涉及到多个锁,但是直接为每个对象自动分配一个锁会带来错误的结果。在这个例子中,锁应该与操作而不是数据关联,所以自动加锁在某些场景下会出问题。

Expand Down
2 changes: 1 addition & 1 deletion lec10-multiprocessors-and-locking/10.5-suo-yu-xing-neng.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

如果你拆分了锁,你可能需要重写代码。如果你为了获得更好的性能,重构了部分内核或者程序,将数据结构进行拆分并引入了更多的锁,这涉及到很多工作,你需要确保你能够继续维持数据的不变性,你需要重写代码。通常来说这里有很多的工作,并且并不容易。

![](../.gitbook/assets/image%20%28560%29.png)
![](../.gitbook/assets/image%20%28562%29.png)

所以这里就有矛盾点了。我们想要获得更好的性能,那么我们需要有更多的锁,但是这又引入了大量的工作。

Expand Down
4 changes: 2 additions & 2 deletions lec10-multiprocessors-and-locking/10.6-case-study-uart.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

所以现在有了一个缓存,一个写指针和一个读指针。读指针的内容需要被显示,写指针接收来自例如printf的数据。我们前面已经了解到了锁有多个角色。第一个是保护数据结构的特性不变,数据结构有一些不变的特性,例如读指针需要追赶写指针;从读指针到写指针之间的数据是需要被发送到显示端;从写指针到读指针之间的是空闲槽位,锁帮助我们维护了这些特性不变。

![](../.gitbook/assets/image%20%28523%29.png)
![](../.gitbook/assets/image%20%28526%29.png)

我们接下来看一下uart.c中的uartputc函数。

Expand All @@ -22,7 +22,7 @@

接下来我们看一下uartstart函数,

![](../.gitbook/assets/image%20%28534%29.png)
![](../.gitbook/assets/image%20%28536%29.png)

如果uart\_tx\_w不等于uart\_tx\_r,那么缓存不为空,说明需要处理缓存中的一些字符。锁确保了我们可以在下一个字符写入到缓存之前,处理完缓存中的字符,这样缓存中的数据就不会被覆盖。

Expand Down
8 changes: 4 additions & 4 deletions lec10-multiprocessors-and-locking/10.7-shi-xian-suo.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

我们先来看一个有问题的锁的实现,这样我们才能更好的理解这里的挑战是什么。实现锁的主要难点在于锁的acquire接口,在acquire里面有一个死循环,循环中判断锁对象的locked字段是否为0,如果为0那表明当前锁没有持有者,当前对于acquire的调用可以获取锁。之后我们通过设置锁对象的locked字段为1来获取锁。最后返回。

![](../.gitbook/assets/image%20%28491%29.png)
![](../.gitbook/assets/image%20%28492%29.png)

如果锁的locked字段不为0,那么当前对于acquire的调用就不能获取锁,程序会一直spin。也就是说,程序在循环中不停的重复执行,直到锁的持有者调用了release并将锁对象的locked设置为0。

Expand Down Expand Up @@ -32,13 +32,13 @@

接下来我们看一下如何使用这条指令来实现自旋锁。让我们来看一下XV6中的acquire和release的实现。首先我们看一下spinlock.h

![](../.gitbook/assets/image%20%28545%29.png)
![](../.gitbook/assets/image%20%28547%29.png)

如你所见,里面有spinlock结构体的定义。内容也比较简单,包含了locked字段表明当前是否上锁,其他两个字段主要是用来输出调试信息,一个是锁的名字,另一个是持有锁的CPU。

接下来我们看一下spinlock.c文件,先来看一下acquire函数,

![](../.gitbook/assets/image%20%28536%29.png)
![](../.gitbook/assets/image%20%28538%29.png)

在函数中有一个while循环,这就是我刚刚提到的test-and-set循环。实际上C的标准库已经定义了这些原子操作,所以C标准库中已经有一个函数\_\_sync\_lock\_test\_and\_set,它里面的具体行为与我刚刚描述的是一样的。因为大部分处理器都有的test-and-set硬件指令,所以这个函数的实现比较直观。我们可以通过查看kernel.asm来了解RISC-V具体是如何实现的。下图就是atomic swap操作。

Expand All @@ -48,7 +48,7 @@

接下来我们看一下release的实现,首先看一下kernel.asm中的指令

![](../.gitbook/assets/image%20%28526%29.png)
![](../.gitbook/assets/image%20%28528%29.png)

可以看出release也使用了atomic swap操作,将0写入到了s1。下面是对应的C代码,它基本确保了将lk->locked中写入0是一个原子操作。

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ uartputc函数会acquire锁,UART本质上就是传输字符,当UART完成了

但是对于并发执行,很明显这将会是一个灾难。如果我们将critical section与加锁解锁放在不同的CPU执行,将会得到完全错误的结果。所以指令重新排序在并发场景是错误的。为了禁止,或者说为了告诉编译器和硬件不要这样做,我们需要使用memory fence或者叫做synchronize指令,来确定指令的移动范围。对于synchronize指令,任何在它之前的load/store指令,都不能移动到它之后。锁的acquire和release函数都包含了synchronize指令。

![](../.gitbook/assets/image%20%28489%29.png)
![](../.gitbook/assets/image%20%28490%29.png)

这样前面的例子中,x<-x+1就不会被移到特定的memory synchronization点之外。我们也就不会有memory ordering带来的问题。这就是为什么在acquire和release中都有\_\_sync\_synchronize函数的调用。

Expand Down
6 changes: 3 additions & 3 deletions lec10-multiprocessors-and-locking/untitled-1.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* 锁可以打包多个操作,使它们具有原子性。我们之前介绍了加锁解锁之间的区域是critical section,在critical section的所有操作会都会作为一个原子操作执行。
* 锁可以维护共享数据结构的不变性。共享数据结构如果不被任何进程修改的话是会保持不变的。如果某个进程acquire了锁并且做了一些更新操作,共享数据的不变性暂时会被破坏,但是在release锁之后,数据的不变性又恢复了。你们可以回想一下之前在kfree函数中的freelist数据,所有的free page都在一个单链表上。但是在kfree函数中,这个单链表的head节点会更新。freelist并不太复杂,对于一些更复杂的数据结构可能会更好的帮助你理解锁的作用。

![](../.gitbook/assets/image%20%28548%29.png)
![](../.gitbook/assets/image%20%28550%29.png)

即使是前面介绍的kfree函数这么一个简单的场景,上面的这些锁的作用都有体现。

Expand All @@ -20,11 +20,11 @@

当有多个锁的时候,场景会更加有趣。假设现在我们有两个CPU,一个是CPU1,另一个是CPU2。CPU1执行rename将文件d1/x移到d2/y,CPU2执行rename将文件d2/a移到d1/b。这里CPU1将文件从d1移到d2,CPU2正好相反将文件从d2移到d1。我们假设我们按照参数的顺序来acquire锁,那么CPU1会先获取d1的锁,如果程序是真正的并行运行,CPU2同时也会获取d2的锁。之后CPU1需要获取d2的锁,这里不能成功,因为CPU2现在持有锁,所以CPU1会停在这个位置等待d2的锁释放。而另一个CPU2,接下来会获取d1的锁,它也不能成功,因为CPU1现在持有锁。这也是死锁的一个例子,有时候这种场景也被称为deadly embrace。这里的死锁就没那么容易探测了。

![](../.gitbook/assets/image%20%28535%29.png)
![](../.gitbook/assets/image%20%28537%29.png)

这里的解决方案是,如果你有多个锁,你需要对锁进行排序,所有的操作都必须以相同的顺序获取锁。

![](../.gitbook/assets/image%20%28567%29.png)
![](../.gitbook/assets/image%20%28569%29.png)

所以对于一个系统设计者,你需要确定对于所有的锁对象的全局的顺序。例如在这里的例子中我们让d1一直在d2之前,这样我们在rename的时候,总是先获取排序靠前的目录的锁,再获取排序靠后的目录的锁。如果对于所有的锁有了一个全局的排序,这里的死锁就不会出现了。

Expand Down
4 changes: 2 additions & 2 deletions lec10-multiprocessors-and-locking/untitled.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ kalloc.c文件中的kfree函数会将释放的page保存于freelist中。

freelist是XV6中的一个非常简单的数据结构,它会将所有的可用的内存page保存于一个列表中。这样当kalloc函数需要一个内存page时,它可以从freelist中获取。从函数中可以看出,这里有一个锁kmem.lock,在加锁的区间内,代码更新了freelist。现在我们将锁的acquire和release注释上,这样原来在上锁区间内的代码就不再受锁保护,并且不再是原子执行的。

![](../.gitbook/assets/image%20%28532%29.png)
![](../.gitbook/assets/image%20%28534%29.png)

之后运行make qemu重新编译XV6,

Expand All @@ -49,7 +49,7 @@ freelist是XV6中的一个非常简单的数据结构,它会将所有的可用

我们来看一下usertest运行的结果,可以看到已经有panic了。所以的确有一些race condition触发了panic。但是如前面的同学提到的,还有一些其他的race condition会导致丢失内存page,这种情况下,usertest运行并不会有问题。

![](../.gitbook/assets/image%20%28553%29.png)
![](../.gitbook/assets/image%20%28555%29.png)

所以race condition可以有不同的表现形式,并且它可能发生,也可能不发生。但是在这里的usertests中,很明显发生了什么。

2 changes: 1 addition & 1 deletion lec11-thread-switching-robert/11.2-xian-cheng-tiao-du.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
* RUNABLE,线程还没有在某个CPU上运行,但是一旦有空闲的CPU就可以运行
* SLEEPING,这节课我们不会介绍,下节课会重点介绍,这个状态意味着线程在等待一些I/O事件,它只会在I/O事件发生了之后运行

![](../.gitbook/assets/image%20%28486%29.png)
![](../.gitbook/assets/image%20%28487%29.png)

今天这节课,我们主要关注RUNNING和RUNABLE这两类线程。前面介绍的定时器中断或者说pre-emptive scheduling,实际上就是将一个RUNNING线程转换成一个RUNABLE线程。通过出让CPU,pre-emptive scheduling将一个正在运行的线程转换成了一个当前不在运行但随时可以再运行的线程。因为当定时器中断触发时,这个线程还在好好的运行着。

Expand Down
6 changes: 3 additions & 3 deletions lec11-thread-switching-robert/11.4-xian-cheng-tiao-du-san.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

但是,实际上switch函数并不是直接从一个内核线程切换到另一个内核线程。XV6中,一个CPU上运行的内核线程可以直接切换到的是这个CPU对应的调度器线程。所以如果我们运行在CPU0,switch函数会恢复之前为CPU0的调度器线程保存的寄存器和stack pointer,之后就在调度器线程的context下执行schedulder函数中(注,后面代码分析有介绍)。

![](../.gitbook/assets/image%20%28503%29.png)
![](../.gitbook/assets/image%20%28504%29.png)

在schedulder函数中会做一些清理工作,例如将进程P1设置成RUNABLE状态。之后再通过进程表单找到下一个RUNABLE进程。假设找到的下一个进程是P2(虽然也有可能找到的还是P1),schedulder函数会再次调用switch函数,完成下面步骤:

Expand All @@ -27,11 +27,11 @@
4. 不论是系统调用也好中断处理程序也好,在从用户空间进入到内核空间时会保存用户寄存器到trapframe对象。所以当内核程序执行完成之后,trapframe中的用户寄存器会被恢复。
5. 最后用户进程P2就恢复运行了。

![](../.gitbook/assets/image%20%28492%29.png)
![](../.gitbook/assets/image%20%28493%29.png)

每一个CPU都有一个完全不同的调度器线程。调度器线程也是一种内核线程,它也有自己的context对象。任何运行在CPU1上的进程,当它决定出让CPU,它都会切换到CPU1对应的调度器线程,并由调度器线程切换到下一个进程。

![](../.gitbook/assets/image%20%28543%29.png)
![](../.gitbook/assets/image%20%28545%29.png)

> 学生提问:context保存在哪?
>
Expand Down
Loading

0 comments on commit 3e81918

Please sign in to comment.