IT笔记与心得

操作系统进程与线程小结

2021-02-19  本文已影响0人  会跳的八爪鱼

概念
1.进程与线程

  • 每个app或者软件启动后都会执行加载程序并执行,一个app执行的过程就是一个进程,操作系统会为进程分配独立的虚拟内存空间与资源。每个进程之间资源不共享。为了解决资源共享的问题,例如视频播放器边下载边解码边播放,在进程中又细分线程。进程是资源分配的基本单位,线程是cpu执行的基本单位。一个进程内的线程共享进程内的资源。但又独立抢占cpu时间片。
    note:为什么不用多进程,而用多线程,一是因为进程上下文切换花销大,同一个进程内的线程上下文切换只需要更改自己独立的寄存器以及栈部分,其余虚拟空间无需改变,二是因为多进程通信不如多线程通信方便。
  • 为了同一时间能够启动多个app,cpu分割了时间片给执行的线程。这种是并发执行,并非并行执行。多核cpu能够并行执行。
    进程的虚拟空间分为内核空间和用户空间,用户空间各个进程独有,内核空间都映射到同一个物理地址,这是进程通信的一种方式。当进程执行系统调用时,会陷入内核态,可以读写内核空间。

2.进程的状态

  • 就绪态:进程分配了资源能够抢占cpu时间片的状态
  • 运行态:进程抢占到cpu时间片,cpu执行的状态
  • 阻塞态:进程因为输入输出IO或者代码约束(wait,sleep)原因,需要阻塞,让出cpu的执行权,这时使用DMA或者通道执行IO操作,IO完成后产生中断事件,进程进入就绪态,可以开始抢占cpu时间片
  • 其他状态
    • 创建状态:进程创建成功进入的状态,这是还没有分配资源,不能抢占cpu
    • 结束状态:进程执行完成
    • 挂起状态:因为计算机内存资源紧张而被换出的进程,分为就绪挂起和阻塞挂起
      • 就绪挂起:当新建一个进程时,因为计算机没有足够的内存分配给进程,所以进入了就绪挂起
      • 阻塞挂起,当进程进入阻塞时,计算机因缺少内存会优先换出阻塞的进程供其他进程使用,这些阻塞进程就进入了阻塞挂起状态
        note:需要进程挂起时会优先考虑优先级,然后考虑阻塞进程,就绪进程(延迟创建)挂起进程因为不在内存中,所以不能执行。


        aa.PNG

        note:阻塞/挂起->阻塞:这种转化在设计中比较少见。如果一个进程没有准备好执行,并且不在内存中,调入它又有什么意义?
        阻塞挂起->就绪挂起:如果等待的事件发生了

3.进程运行以及切换

  • pcb(保存进程标识,状态,打开文件表,进程切换时保存的寄存器信息等)进程信息的结构体,相同状态的pcb以链表的形式连接,形成阻塞队列,就绪队列等。
  • 进程创建后,构造pcb结构体并连接在就绪队列中等待调度
  • 进程阻塞,暂停运行,并将pcb连接到阻塞队列中等待事件完成
  • 进程唤醒,等待事件完成pcb从阻塞队列移除,并连接在就绪队列等待调度
  • 进程上下文切换,将进程寄存器信息保存到pcb中,等现场恢复时读取pcb继续执行
    note:cpu调度实际上是线程的调度,进程只有一个线程则线程的调度相当于进程的调度。

4.线程

  • 为什么要出现线程?当编写word文档时,我可以一边编辑文档一边保存,如果只有进程,那么只能在编写好文档之后才能执行保存动作。
  • 线程是进程中更细粒度的执行单元,在进程中创建,所以进程中的各个线程拥有相同的用户地址空间,只有堆栈信息,寄存器和程序计数器不同。
  • 线程切换只需要将执行线程的寄存器信息和程序计数器送往cpu,并还原堆栈信息即可完成新线程切换。

5.线程模型

  • 用户级线程:在用户空间创建,销毁和切换线程,不需要内核的参与。在用户空间内创建,以进程的名义申请cpu时间片,然后进程根据自身的线程调度算法调度线程。内核感知不到进程内的线程,线程控制表存放在用户空间(线程创建销毁和调度都属于用户空间,只有系统调用的时候才需要内核态的参与)。
    • 优点:只需要在用户空间上调度线程,不需要内核态与用户态的切换,可以自己制定调度算法。
    • 缺点:不能进行系统调用,需要通过中间平台运行时系统调用系统。由于内核感知不到线程,所以只能以进程为单位分配时间片。一旦线程阻塞,则该进程中的其他线程都不能执行,不能充分利用多核。
  • 内核级线程:在内核中创建,销毁并管理的线程,所以需要转换成内核态执行线程管理。
    • 优点:充分利用多核,能够利用时钟中断进行时间片轮询。缺点:线程管理代价大,需要由用户态转到内核态,内核创建销毁线程。再由内核态转为用户态,线程控制表存放在内核空间,所以内核线程数会受到限制。


      用户线程与内核线程的区别
  • note:用户级线程的线程控制(tcb:存放线程控制寄存器及堆栈信息的)表在用户空间中,而内核级线程的线程控制表在内核态中,由内核调度,所以内核线程管理需要转换到内核态。
  • lwp(轻量级进程):轻量级线程(LWP)是一种由内核支持的用户线程。它是基于内核线程的高级抽象,因此只有先支持内核线程,才能有LWP。每一个进程可以有一个或多个LWPs,每个LWP由一个内核线程支持。它位于用户层和系统层之间。系统对线程资源的分配、对线程的控制是通过轻进程来实现的,一个轻进程可以控制一个或多个线程。CPU时间片的调度是面向轻进程的。
  • 线程模型:用户执行系统调用时需要进入内核态,当我们使用不同的线程执行系统调用时,会有不同的阻塞情况。
    • 多对一模型:用户线程使用系统调用可以是两种方式,一是通过运行时系统执行系统调用,二是通过lwp建立关联。第一种情况这样的影响是一个用户线程io阻塞,则整个进程都将阻塞(内核感受不到线程存在,会阻塞进程,因为内核中没有线程表,只有进程表会阻塞整个进程,让其他进程执行)。第二种情况下lwp成为cpu时间片分配的单位,但是如果进程内的所有线程都关联同一个lwp,则和第一种情况相同。
    • 一对一模型:使用内核线程,或者每个用户线程都关联不同的lwp,这样任何一个线程阻塞,都不会影响其他线程的调度。
    • 多对多模型:lwp作为用户线程和内核线程关联的桥梁,一个进程中可以有多个lwp,一个lwp可以有多个用户线程,lwp有关联一个内核线程,这样一个用户线程的io阻塞,不会影响整个进程。这种属于用户线程与内核线程混合使用的方式
  • note:java中的线程属于内核及线程,原因有两点,第一进程内的单个线程阻塞不会影响其他线程的运行。第二基本没有办法控制线程的执行顺序以及执行次数。我遵照下面的程序编写了1000个线程同时睡眠一分钟,然后任务管理器中的线程数就从三千多瞬间升到四千多,这也说明java线程属于内核及线程。所以java线程的上下文切换消耗很大。
public class ThreadTest {
    public static void main(String[] args) {
        for (int i = 0; i < 1000; i++) {
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        TimeUnit.SECONDS.sleep(120);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "正在执行任务");
                }
            });
            thread.start();
        }
    }
}

5.调度算法

  • 非抢占式:线程执行完成或者阻塞后让出cpu使用权
  • 抢占式:在某段时间结束后,线程如果没有执行完或者阻塞,发生时钟中断。挂起改成供其他线程使用。

其他

smp:对称处理器,多核cpu中的每个cpu地位相同,都可以完整访问内存和io设备

参考:https://blog.csdn.net/freeelinux/article/details/53562592(挂起状态)
https://mp.weixin.qq.com/s/YXl6WZVzRKCfxzerJWyfrg(进程知识点)
https://www.jianshu.com/p/49e3e47d41f0 (线程模型)
https://www.cnblogs.com/feng9exe/p/6803257.html(线程种类及模型)
https://blog.csdn.net/lihaidong1991/article/details/88861123(线程模型)
https://www.cnblogs.com/feng9exe/p/7890934.html(线程)
https://www.zhihu.com/question/307787570(用户级线程的作用)

上一篇下一篇

猜你喜欢

热点阅读