1 用户级线程的概念
线程是在一个地址空间下启动并交替执行的程序,用户级线程用用户管理。
2 用户级线程的设计和实现
2.1 用户级线程切换Yield()
线程1,线程2如下所示,在线程1中调用Yield()来切换到线程2

进程的执行过程为
A() -> B() -> Yield() ->线程2-> C() -> D() -> Yield()
下面讨论如何实现Yield()
2.1.1 为什么先设计Yield()而不是ThreadCreate()
只要把一段程序做成可以用Yield切换进来的样子,并且CPU的进入点是这段程序的首地址,这段程序就可以执行了。所以创建一个用户级线程就是创建一个可以让CPU切换进去的初始样子。
2.1.2 Yield的第一个版本和缺陷
在B()中Yield()直接执行jmp 300。
Yield(2){
jmp 300;//300可以用TCB记录,jmp TCB(1).EIP
}
在C()中Yield()直接执行jmp 204。
Yield(1){
jmp 204;//204可以用TCB记录
}
此时进程的返回地址栈变化如下

D中执行完Yield(1)之后,进入204往下执行,一直执行到B函数的“ } ”,执行ret指令,弹出的是404,发生了错误!(应该是回到A函数中继续执行)。所以,直接jmp是行不通的!
2.1.2 Yield的第二个版本和缺陷
上述问题显然是由于两个线程共用一个栈产生的,解决办法当然是给每个线程都分配一个栈。用线程的TCB来存储线程的esp(不用存储ebp,因为可以公用一个ebp)
两个栈的图示如下

B中的Yield代码自然的想法就是不仅要切换PC到C的地址300去执行,还要修改当前esp为线程2的esp,代码如下
Yield(2){
tcb1.esp = esp;
esp = tcb2.esp;
jmp 300;//jmp esp.EIP
}
D中的Yield代码为
Yield(1){
tcb2.esp = esp;
esp = tcb1.esp;
jmp 204;//jmp esp.EIP
}
执行过程中的返回地址压栈如图所示

此时又出现问题了,D()中执行Yield()时遇到jmp 204,便开始顺着204朝下执行,但是在遇到B的" } “时,执行ret,栈弹出的是204,又返回到了204执行,这出现了错误。这个错误的原因在于Yield的 } 没有被执行。回顾刚刚的过程,204被压栈是因为要去执行Yield,但是Yield的” } "并没有被执行。
2.1.3 Yield的第三个版本
解决的办法就是删去Yield()中的jmp 204,因为这样就可以使得Yield的" } “得到执行,最重要的,这个” } "与jmp 204有着同样的效果。
B中的yield代码如下
Yield(2){
tcb1.esp = esp;
esp = tcb2.esp;
}
D中的yield代码如下
Yield(1){
tcb2.esp = esp;
esp = tcb1.esp;
}
返回地址栈的过程如下

总结如下:
- 用户级线程的切换就是在切换位置上调用Yield()
- Yield干的事情如下
- 将当前的执行现场保存在当前线程的TCB中
- 找到下个线程的的TCB的栈指针
- 在下个线程的栈中弹出下个线程的执行现场
用C语言来描述如下
Yield(){
next = FindNext();
push %eax
push %ebx
....
mov %esp,TCB[current].esp
mov TCB[current].esp,%esp
....
pop %ebx
pop %eax
}
2.2 用户级线程创建函数ThreadCreate()
ThreadCreate(funcA)的核心功能如下:
- 创建一个TCB,用来存储funcA的执行现场信息
- 创建一个funcA的执行栈,栈的第一个压入的元素应该是funcA的起始地址,这样当别的线程执行Yield(A)时候,使用“ } ”的ret指令便可以开始执行funcA
- 把TCB和funcA的栈关联起来

ThreadCreate的核心代码如下
void ThreadCreate(A){
TCB * tcb = malloc();
Stack * stack = malloc();
*stack = A;
tcb.esp = stack;
}
3 (精华)工程上真正的实现用户级线程
3.1 环境配置
| 名称 | 配置 |
|---|---|
| 操作系统 | win 10(64位) |
| 编译器 | MingGW 3.2.3(32位 老古董了) |
3.2 实现目标
在屏幕上交替打印出A和B。即要让以下代码
void A(void * args){
int A = (long)args;
while(A-- > 0){
printf("A");
Yield();
}
}
void B(void * args){
int A = (long)args;
while(A-- > 0){
printf("B"

最低0.47元/天 解锁文章
2151





