Operating Systems-tep Chapter3 读书笔记

并发性简介

每一个线程很像一个独立的进程,但是与进程的区别是:进程内的各个线程共享相同的地址空间。所以各个线程可以访问相同的数据。

线程有一个程序计数器(PC)来跟踪程序从何处去指令。每个线程有自己的用于计算的寄存器集。

当从一个线程切换到另一个线程时,会发生上下文切换,保存线程T1的寄存器状态,在T2运行之前加载T2的寄存器状态(状态保存在线程控制块TCB(thread control blocks)),线程上下文切换线程的地址空间依旧不变。

在单线程进程地址空间的简单模型中,有一个单独的栈,通常位于地址空间的底端,在多线程进程地址空间中,每一个线程都有一个栈。

下面是单线程进程与两个线程进程的地址空间比较:

在这里插入图片描述

失控的调度

在这里插入图片描述

上面的程序创建了两个子线程,子线程对counter进行++操作,执行1e7次,主线程等待两个子线程执行结束后输出counter的值。按道理来说counter的值是2*1e7,但是发现比正确答案少很多。书上通过指令序列解释了为什么会这样:

counter++ 操作有如下三条指令序列:

在这里插入图片描述

假设counter分配的地址是0x8049a1c, 首先mov指令将0x8049a1c内存的值写入寄存器eax中,然后将eax中的值+1,最后将eax中的值写回0x8049a1c中。

下面有两个线程(T1和T2),假设0x8049a1c中的值为50,T1进入这段代码,对counter进行+1操作,它首先拿到counter的值(mov指令),然后进行+1操作(add指令),eax中的值为51,这时定时器中断到达,操作系统将保存T1线程的状态(PC,eax等寄存器)至线程TCB。之后线程T2被调度执行,执行这三条指令,执行mov指令读的还是原来的50,之后进行后两条指令,将0x8049a1c的值更新为51,当T2执行完后,T1执行最后一条指令,将0x8049a1c的值更新为51。counter++操作明明执行了两次,但初值为50的counter的值只有51.

上面已经示范的问题称作:竞争条件,其结果取决于这段代码的执行时机。多线程中,一段代码的执行会引起竞争条件,我们称这段代码为:临界区。一个临界区是一段访问共享变量(更一般的:共享资源)且不可被多于一个线程并发执行的代码段。

原子性的愿望

解决上面所述问题的一个办法是使用一个更强大的指令,这个指令可以在单步之内做我们需要做的。我们可以假设有这样一条指令代替上面的三条指令:

在这里插入图片描述

这样不管是否被中断,这条指令要么执行要么不执行,这样就保证不会出现问题了。

原子性意味着“作为一个单位”,有时称之为“全或无”

但是并不是所有的指令都可以合成一个有效的指令,但我们可以借助硬件提供的有效指令构建一系列通用的同步原语。通过这些硬件同步原语与操作系统的支持,我们可以构造出以同步可控方式访问临界区的多线程代码。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值