13.线程的引出与实现

1.回顾

程序开始执行,PC置初值,CPU就不断地 取指执行
顺序执行,CPU如果遇到 耗时的指令,就在等待,没有充分利用,引出了 任务切换

1.1 栈实现跳转

这里写图片描述

1.2 一个栈 + Yield 造成的混乱

这里写图片描述

D执行完,回不到 204

1.3 两个栈 + 两个用户TCB

这里写图片描述

切换时,Yield找到 新的用户线程的TCB,找到新的用户栈,切换

1.4 内核栈切换

这里写图片描述

用户栈 关联着 内核栈,切换时,从用户栈 到 内核栈,到TCB,切换 内核栈,再实现 切换 用户栈

2.内核栈切换的实现:屏幕交替打印 A 和 B

2.1 AB.c

main()
{
    //打印 A
    if(!fork())
    {
        while(1)
            printf("A");
    }

    // 打印 B
    if(!fork())
    {
        while(1)
            printf("B");
    }

    wait();
}

2.2 计算机执行过程

这里写图片描述

fork:
    mov __NR_fork, %eax
    int 0x80

set_system_gate(0x80, &system_call)
system_call:
            sys_fork
    100: mov %eax, res
         cmpl res, 0
         jne 208
         cmpl $0, state(current)
         jne reschedule
         iret
sys_fork:
    pushl ...
    call copy_process
    ret

200: printf("A")
     jmp 200

208: ...
304: wait()

fork中有int 0x80中断,通过中断进入内核,形成了 对应的用户栈 和 内核栈,执行 system_call
system_call 先调用 sys_fork,sys_fork 调用 copy_process
copy_process 会在内核中 做一个新的PCB,做出新的 内核栈,eip 对应的代码就是 打印A
fork出新的进程,cmpl res, 0,res == 0 执行 200:打印A,res !=0,执行208
执行完 copy_process,父进程就要返回了,cmpl $0, state(current),执行 reschedule,屏幕打印A

创建完了 打印A 的进程,没有阻塞,还有时间片,就可以创建 下一个 子进程了
创建 打印B的进程 与 打印A的进程类似,只是 eip 对应的是 打印B的指令

现在有2个子进程都在 就绪队列中

创建了 2个 子进程,main 执行 wait,开始等待,就是将自己的state 设为 阻塞态,调用 schedule, switch_to 切换到下一个进程,switch_to通过 TSS 完成栈的切换,当前线程的 TSS = CPU的 TSS,CPU的 TSS = 下一个线程的

main(){

...
wait();// 又是 mov __NR_wait   int 0x80

system_call:
call sys_waitpid

sys_waitpid() // exit.c中
current->state=TASK_INTERRUPTIBLE;
schedule();

schedule(){
if((*p)->state == TASK_RUNNING && (*p)->counter > c)
c = (*p)->counter, next = i;
...
switch_to(next);

}

A执行打印A,B执行打印B,怎么能交替执行呢?

2.3 时钟中断实现交替打印

需要在内核中有一个调度点,比如通过 时钟中断

// shced.c
void shed_init(void)
{
    set_intr_gate(0x20, &timer_interrupt);
}

void _timer_interrupt:
    ...
    call do_timer

void do_timer(...)
{
    if((--current->counter > 0))
        return;
    current-> counter = 0;
    schedule();
}

时钟中断,每到中断,执行 do_timer,counter–,当counter == 0,调 schedule,调度一次

main()
{
    mov __NR_fork, %eax
    int 0x80

100 : mov %eax, res
      cmpl res, 0
      jne 208

200: printf("A")
     jmp 200

208:... 300 :printf("B")
             jmp 300

308: wait()

}

设 counter = 0,时间片用完了,A不执行,调用schedule 进程 switch_to 切换到B
B.eip = 300, A.eip = 200
B切换到A,还需要中断

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值