进程 线程 协程 简单介绍

发布时间 2023-09-14 15:05:48作者: 小海哥哥de

一、进程

1.1 进程可看做是正在执行的程序

进程需要一定的资源(如 CPU、时间、内存、文件和 I/O 设备)来完成其任务。 这些资源在创建进程或者执行进程时被分配。

1.2 进程的组成有:PCB、程序段、数据段。

  • PCB(进程控制块,process control block): 保存进程运行期间相关的数据,是进程存在的唯一标志。
  • 程序段: 能被进程调度程序调度到 CPU 运行的程序的代码段。
  • 数据段: 存储程序运行期间的相关数据,可以是原始数据也可以是相关结果。

1.3 进程在执行时会改变状态,进程的状态有 5 种:

  • 创建:进程正在被创建。
  • 运行:指令正在被执行。
  • 等待:阻塞,进程等待某个事件的发生(如 I/O 完成或收到信号)。
  • 就绪:进程等待分配处理器。
  • 终止:进程完成执行

二、线程

2.1 进程是系统资源分配基本单位,线程是处理器(CPU)调度的基本单位。

通常情况下,一个进程里面只有一个控制流,但是在现代的系统中,为了充分的利用系统资源,一个进程实际上是可以有多个称为线程的执行单元的,每一个线程都运行在进程的上下文(进程地址空间)中,一个进程中的线程除了自己独有的数据之外,都是共享同一个进程里面的数据的,故在多线程之间共享数据比在多进程之间共享数据容易很多。进程在实现上有分为内核级线程和用户级线程,以及内核级和用户级混合的线程。在Linux系统中,是没有真正意义上的线程的,它将线程的实现为一个轻量级的进程,其通过在进程之间共享数据的方式来实现线程的。相对于Linux系统的其他系统,比如windows系统就实现了区别于进程的线程。

2.2 要理解线程调度的两种方式:

  • 协作式调度:当前线程完全占用CPU时间,除非自己让出时间片,直到运行结束,系统才执行下一个线程。可能出现一个线程一直占有CPU,而其他线程等待。
  • 抢占式调度:操作系统决定下一个占用CPU时间的是哪一个线程,定期的中断当前正在执行的线程,任何一个线程都不能独占。不会因为一个线程而影响整个进程的执行。

操作系统的核心是内核(kernel),它独立于普通的应用程序,可以访问受保护的内存空间,也有访问底层硬件设备的所有权限。有些CPU 的指令是非常危险的,一旦用错可能导致系统崩溃。如果所有的程序都可以任意使用这些指令,那么系统崩溃的概率将大大增加。为了保证内核的安全,操作系统一般都禁止用户进程直接操作内核。具体的实现方式是将虚拟内存空间划分为两部分,一部分为内核空间,另一部分为用户空间。当进程运行在内核空间时就处于内核态,进程运行在用户空间时则处于用户态。

无论是进程还是线程,它们的上下文切换和"内核态、用户态"没有直接的关系。比如只要需要系统调用,即使不做任何切换,都需要进入内核态。举个例子:一个线程调用函数在屏幕上打印 hello world,就已经进入了内核态了,因为打印字符的功能是由内核程序提供的。总的来说,应用程序通常运行在用户态,遇到下列三种情况会切换到内核态:

系统调用:创建和调度线程、加锁解锁等等。
异常事件:发生不可知的异常时切换到内核态,以执行相关的异常事件。
设备中断:如果外围设备完成了用户请求,比如硬盘读写操作,就会给CPU发送中断信号。CPU会转去处理中断事件,切换到内核态。
线程的代码在用户态运行,而调度是在内核态运行的。

2.3 操作系统切换线程上下文的步骤如下所示:

1)保留用户态现场(上下文、寄存器、用户栈等)
2)复制用户态参数,用户栈切到内核栈,进入内核态
3)代码安全检查(内核不信任用户态代码)
4)执行内核态代码
5)复制内核态代码执行结果,回到用户态
6)恢复用户态现场(上下文、寄存器、用户栈等)

三、协程

3.1 协程:一般称协程为轻量级线程。

对于操作系统来说,内核只“认识”进程和线程,对于协程的存在,内核是不知道的,需要用户负责协程的创建、调度和销毁,因此,协程又被称为用户级线程。

3.2 协程的性质:

  • 协程是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方(一般是自定义的数据结构中),在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。
  • 对操作系统而言,线程是最小的执行单元,进程是最小的资源管理单元。无论是进程还是线程,都是由操作系统所管理的。
  • 协程不是被操作系统内核所管理的,而是完全由程序所控制,也就是在用户态执行。这样带来的好处是性能大幅度的提升,因为不会像线程切换那样消耗资源。
  • 协程既不是进程也不是线程,协程仅仅是一个特殊的函数,协程它进程和进程不是一个维度的。
  • 一个进程可以包含多个线程,一个线程可以包含多个协程。
  • 一个线程内的多个协程虽然可以切换,但是多个协程是串行执行的,只能在一个线程内运行,没法利用 CPU 多核能力。
  • 协程与进程一样,切换是存在上下文切换问题的。

资料:
http://m.rookiew.com/mirrors/4039.html
https://zhuanlan.zhihu.com/p/569273620?utm_id=0
https://zhuanlan.zhihu.com/p/446993465
https://blog.csdn.net/m0_37851345/article/details/119023413