进程与线程

多线程 专栏收录该内容
2 篇文章 0 订阅

进程与线程

进程

进程,直观点说,保存在硬盘上的程序运行以后,会在内存空间里形成一个独立的内存体,这个内存体有自己独立的地址空间,有自己的堆,上级挂靠单位是操作系统。操作系统会以进程为单位,分配系统资源(CPU时间片、内存等资源),进程是资源分配的最小单位。

进程是一个具有一定独立功能的程序在一个数据集上的一次动态执行的过程,是操作系统进行资源分配和调度的一个独立单位,是应用程序运行的载体。进程是一种抽象的概念,从来没有统一的标准定义。进程一般由程序、数据集合和进程控制块三部分组成。程序用于描述进程要完成的功能,是控制进程执行的指令集;数据集合是程序在执行时所需要的数据和工作区;程序控制块(Program Control Block,简称PCB),包含进程的描述信息和控制信息,是进程存在的唯一标志。

线程

线程是进程的一个实体,是CPU调度和分派的基本单位。它是比进程更小的能独立运行的基本单位。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。

在早期的操作系统中并没有线程的概念,进程是能拥有资源和独立运行的最小单位,也是程序执行的最小单位。任务调度采用的是时间片轮转的抢占式调度方式,而进程是任务调度的最小单位,每个进程有各自独立的一块内存,使得各个进程之间内存地址相互隔离。

后来,随着计算机的发展,对CPU的要求越来越高,进程之间的切换开销较大,已经无法满足越来越复杂的程序的要求了。于是就发明了线程,线程是程序执行中一个单一的顺序控制流程,是程序执行流的最小单元,是处理器调度和分派的基本单位。一个进程可以有一个或多个线程,各个线程之间共享程序的内存空间(也就是所在进程的内存空间)。一个标准的线程由线程ID、当前指令指针(PC)、寄存器和堆栈组成。而进程由内存空间(代码、数据、进程空间、打开的文件)和一个或多个线程组成。

线程与进程的区别

  1. 地址空间:线程是进程内的一个执行单元,进程内至少有一个线程,它们共享进程的地址空间,而进程有自己独立的地址空间
  2. 资源拥有:进程是资源分配和拥有的单位,同一个进程内的线程共享进程的资源
  3. 线程是处理器调度的基本单位,但进程不是
  4. 二者均可并发执行
  5. 每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口,但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制

线程的状态

在这里插入图片描述

根据上图我们可以很简单的将一个调度实例划分为简单的3个状态,它们分别为新建、就绪、运行中、阻塞、死亡。

  • 新建:一个新的线程被创建,等待该线程被CPU调用执行;
  • 就绪: 代表当前的调度实例在可执行队列中,随时可以被切换到占用处理器的运行状态。
  • 运行:代表当前的调度实例正在占用处理器运行中。
  • 阻塞:代表当前的调度实例在等待相应的资源。
  • 死亡:一个线程完成任务或者其他终止条件发生,该线程终止进入退出状态,退出状态释放该线程所分配的资源。

下面我们分别深入的理解这几个状态。 就绪/运行两个状态是由调度器根据调度算法来进行切换的,我们通常所指的调度算法实际上主要控制的是调度实例的就绪/运行之间切换的方法,比如是否可以抢占,是否按照时间片轮流调度,是否按照优先级来调度等等,所以调度算法主要控制的是这两个状态之间的切换。

而就绪/运行这两个状态代表当前此调度实例没有依赖于任何系统资源,它可以随时得到执行,相对应的阻塞状态指的就是当前调度实例依赖于某个系统资源并且没有得到满足,所以当前的调度实例被阻塞,并且在资源满足前永远不会得到运行。

在什么情况下调度实例会进入阻塞状态呢, 这个有很多种情况,比如当前的用户态线程调用了阻塞版本的recv函数,并且当前的TCP链接中没有收到数据,那么此用户态线程就会被标记为阻塞状态,并且休眠在socket的recvbuff之上,而当内核协议栈收到数据包并且将数据成功放入socket的recvbuff之后会唤醒阻塞在此休眠队列的调度实例从而将此用户态线程放入到就绪队列,然后等待调度算法调度其运行。此外比如线程的mutex/sleep/读写文件/管道操作/…等都会有线程被阻塞的可能。

但是不论阻塞在何种资源之上,内核中都不应该出现复杂的调度实例状态设计,比如曾经遇到过一个系统的内核其中的阻塞状态分为,Blocked On Signal/ Blocked on Msg/ Blocked On Sem/…等5个不同的阻塞的状态,这种是典型的将调度实例的状态和等待的资源混淆在了一起,这是一种很失败的设计,如果系统中多了一种新的IO资源其就会需要增加一种新的线程状态。

正确的做法是不论当前调度实例在等待何种资源,其都只有一种阻塞状态,而通过其调度实例控制块中的等待队列来具体区分其在等待的实际系统资源是什么。 在这种设计中,如果有新的阻塞系统资源加入,只需要将等待队列的指针赋值到新的阻塞资源之上就可以了,从而避免了上面复杂的调度实例状态设计。

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
©️2020 CSDN 皮肤主题: Age of Ai 设计师:meimeiellie 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值