# 自底向上理解多线程
# 操作系统对CPU的调度
操作系统也是软件,也是一大堆程序组成的,所以不要觉得它多么神秘。既然是程序,程序又是由一条条各种这台计算机所支持的指令构成的,执行程序就袭是执行这一条条指令。 中央处理器(CPU)工作都可以分为5个阶段:取指令、指令译码、执行指令、访存取数、结果写回。
由于处理器的运行速度远远大于I/O,以至于内存中所有进程都等待I/O的情况更加常见,因此,可以在处理器等待I/O的时候处理进行下一个指令。
由于存在一些处于非运行状态下的但已经等待准备就绪的线程,二同时存在另外一些处于堵塞装袋等待 I/O的进程,为了解决这个问题便采用了五状态模型即:运行态,就绪态,堵塞/等待态,新建和退出态
新状态:进程已经创建,但未被OS接纳为可执行进程。(还没有申请到相应的资源)。
就绪态:进程做好了准备,准备执行(只等待处理机)。
执行状态:该进程正在执行(单处理机,某一时刻仅一个进程占用处理机)。
阻塞状态:等待某事件发生才能执行,如等待I/O完成。
终止状态.
# 时间片与时钟周期
时钟周期是计算机中最基本的、最小的时间单位。在一个时钟周期内,CPU仅完成一个最基本的动作。 从小到大来说:时钟周期,CPU周期,指令周期,CPU时间片
时钟周期:一个脉冲需要的时间,频率的倒数 CPU周期:读取一个指令节所需的时间 指令周期:读取并执行完一个指令所需的时间 CPU时间片:CPU分给每个进程的时间
详细了解参看: https://www.jianshu.com/p/96770425d37a
# 进程状态与指令重排
指令重排是指在程序执行过程中, 为了性能考虑, 编译器和CPU可能会对指令重新排序.
CPU指令重排 一条汇编指令的执行是可以分为很多步骤的, 分为不同的硬件执行
取指 IF
译码和取寄存器操作数 ID
执行或者有效地址计算 EX (ALU逻辑计算单元)
存储器访问 MEM
写回 WB (寄存器)
既然指令可以被分解为很多步骤, 那么多条指令就不一定依次序执行. 因为每次只执行一条指令, 依次执行效率太低了, 假设上述每一个步骤都要消耗一个时钟周期, 那么依次执行的话, 一条指令要5个时钟周期, 两条指令要占用10个时钟周期, 三条指令消耗15个时钟.
而如果硬件空闲即可执行下一步, 类似于工厂中的流水线, 一条指令要5个时钟周期, 两条指令只需要6个时钟周期, 因为是错位流水执行, 三条指令消耗7个时钟.
举个例子 A = B + C, 需要如下指令
- 指令1 : 加载B到寄存器R1中
- 指令2 : 加载C到寄存器R2中
- 指令3 : 将R1与R2相加, 得到R3
- 指令4 : 将R3赋值给A
注意下图红色框选部分, 指令1, 2独立执行, 互不干扰. 指令3依赖于指令1, 2加载结果, 因此红色框选部分表示在等待指令1, 2结束. 待指令1, 2都已经走完MEM部分, 数据加载到内存后, 指令3继续执行计算EX. 同理指令4需要等指令3计算完, 才可以拿到R3, 因此也需要错位等待.
再来看一个复杂的例子 a = b + c d = e - f 具体指令执行步骤如图, 不再赘述, 与上图类似, 在执行过程中同样会出现等待.
这边框选的X统称一个气泡, 有没有什么方案可以削减这类气泡呢. 答案自然是可以的, 我们可以在出现气泡之前, 执行其他不相干指令来减少气泡. 例如可以将第五步的加载e到寄存器提前执行, 消除第一个气泡, 同理将第六步的加载f到寄存器提前执行, 消除第二个气泡. 经过指令重排后, 整个流水线会更加顺畅, 无气泡阻塞执行. 原先需要14个时钟周期的指令, 重排后, 只需要12个时钟周期即可执行完毕. 指令重排只可能发生在毫无关系的指令之间, 如果指令之间存在依赖关系, 则不会重排. 指令重排可能产生的问题: 1.无法识别带有隐式因果关系的指令 有些程序逻辑,单纯从上下文是看不出它们的因果关系的。比如: addr=5;val=data; 从表面上看,addr和data是没有什么联系的,完全可以放心的去乱序执行。但是如果这是在某某设备驱动程序中,这两个变量却可能对应到设备的地址端口和数据端口。并且,这个设备规定了,当你需要读写设备上的某个寄存器时,先将寄存器编号设置到地址端口,然后就可以通过对数据端口的读写而操作到对应的寄存器。那么这么一来,对前面那两条指令的乱序执行就可能造成错误。
# 多线程
我们通常将每个任务(Task)称为一个进程(Process),而一个进程可以包含多个顺序执行流,每个执行流就是一个线程(Thread)。线程并不是程序,它本身并不能运行,必须依托程序运行,多线程意味着一个程序内部有多条语句并发执行; 并发执行的含义是操作系统将管理的时间片平均地分配给每一个线程,从而保证所有的线程都能够在极短的时间内得到处理;一个时间片只能执行一个线程,由于时间片是一个很小的时间单位,而CPU的处理速度又非常快,加之线程的运算量并不是特别大,因此操作系统能在很短的时间内切换线程,所有我们看起来就好像是多个线程并发执行的。实际上CPU仍是串行执行线程的。 程序在运行时会转换为一个或多个进程,进程是一个动态的概念,每一个进程都会占用一定的系统资源和内存空间,并且各个进程之间是相互独立的,从而计算机可以同时运行多个程序。
线程可以说是一种轻量级的进程,线程是进程的组成单元,一个进程可以拥有多个线程
多线程技术也是为了支持 并发 操作,最大限度的提高CPU利用率;线程也要抢占系统资源,与其他的线程争夺CPU的使用权;
# 多线程的优势
1.相对多任务来讲,多个线程能够直接共享数据和资源,多线程编程简单、效率高、能够轻易实现线程之间的通信;
2.在网络开发中,每个客户端与服务器连接时,就相当于服务器开辟了一个新线程,因此多线程适合开发服务程序;
3.多线程技术适合于开发有多种交互接口的程序,如聊天程序、网络下载工具等;
4.适合于有人机交互又有计算量的程序,由于程序频繁交互,事件众多,是由多线程可以减少编写此类程序的困难,提高程序吞吐
量。
参考文章:
https://www.cnblogs.com/xdecode/p/8948277.html
https://blog.csdn.net/lindanpeng/article/details/72459493
https://blog.csdn.net/weixin_30932215/article/details/98539975
https://www.cnblogs.com/yzjT-mac/p/6054457.html?utm_source=itdadao&utm_medium=referral