文章目录
- 进程和线程
- 进程的概念
- 进程和程序的区别
- PCB(进程控制块)
- 程序是如何运行的
- 进程的特征
- 进程的状态和状态转换
- 五态模型
- 进程控制
- 进程状态装换为啥需要保证原子性
- 如何实现原语的原子性?
- 进程控制相关原语
- 进程创建
- 进程终止
- 进程的阻塞和唤醒
- 进程的唤醒
- 进程的切换
- 进程通信
- 共享存储
- 消息传递
- 管道通信
- 线程概念
- 为啥要引入线程
- 线程的属性
- 线程的实现方式
- 用户级线程
- 内核级线程
- 多线程模型
- 一对一模型
- 多对一模型
- 多对多模型
- 线程的状态和转换
- 线程的组织与控制
- 进程和线程的区别
进程和线程
进程的概念
程序:是静态的,就是一个存放在磁盘里的可执行文件,就是一系列的指令集合。
进程:是动态的,是程序的一次执行过程。在现在的操作系统中,用户程序以进程方式占用系统资源。
典型的进程定义:
- 进程是程序的一次执行
- 进程是一个程序以及其数据在处理机上顺序执行时所发生的活动
- 进程是系统进行资源分配和调度的一个独立单位
操作系统负责创建进程,为进程分配资源、调度进程占用处理机等。
进程和程序的区别
- 进程是动态的,程序是静态的:程序是有序代码的集合,通常对应着文件、静态和可以复制。进程是程序的执行
- 进程是暂时的,程序是永久的,进程是一个状态变化的过程,程序可长久保存。
- 进程与程序组成不同:进程的组成包括程序、数据和PCB(进程控制块),PCB是进程存在的唯一标志
- 进程与程序的对应关系:进程是程序在数据集上的一次执行,通过多次执行,一个程序可以对应多个进程,通过调用关系,一个进程可以包括多个程序。
举个例子:正在运行的QQ音乐是一个进程,正在登录微信也是一个进程。同时登录多个QQ就是多个不同的进程。
PCB(进程控制块)
PCB是进程存在的唯一标志,当进程被创建时,操作系统就会为其创建PCB,但你进程结束时,会回收其PCB。
当进程被创建时,操作系统会为该进程分配一个唯一的、不重复的进程id,叫做pid。
- 操作系统要记录PID、进程所属用户ID(UID),PID用来区分不同的进程
- 还要记录给进程分配了哪些资源(如:分配了多少内存、正在使用哪些I/O 设备、正在使用哪些文件),可以用于实现操作系对资源的管理
- 还要记录进程的运行情况(如:CPU使用时间、磁盘使用情况、网络流量使用情况等),可以用于实现操作系统对进程的调度
这些信息都要被保存在一个数据结构PCB中,PCB也叫做进程控制块。操作系统需要对各个并发运行的进程进行管理,但凡管理时所需要的信息,都会被放到PCB中
PCB包含以下信息:
-
进程标识符
- 外部标识符:创建者提供,便于记忆,比如进程名(可以基于执行的文件名)
- 内部标识符:系统为每个进程分配一个唯一的pid
-
处理机状态信息
处理机在运行时,许多信息都放在寄存器中。当处理机被中断时,所有这些信息都必须保存在PCB 中,以便在该进程重新执行时,能从断点继续执行。
- 通用寄存器:用户访问,用于暂存信息(进程运行的现场信息
- 指令计数器:存放了进程下执行的下一条指令的地址
- 程序状态字:含有状态信息,如条件码,执行模式,中断屏蔽标志
- 用户栈指针:指每个用户进程都有一个或若千个与之相关的系统栈,用存放过程和系统调用参数及调用地址,栈指针指向该栈的栈顶。过程调用/系统调用/中断处理和返回时需要用
-
进程调度(控制和管理)信息
- 进程状态,指明进程的当前状态,作为进程调度和对换时的依据;
- 进程优先级,用于描述进程使用处理机的优先级别的一个整数,优先级高的进程应优先获得处理机;
- 进程调度所需的其它信息,它们与所采用的进程调度算法有关,比如,进程已等待 CPU 的时间总和、进程已执行的时间总和等;事件,阻塞原因
-
进程控制信息(资源分配清单)
- 程序和数据的地址;
- 进程同步和通信机制:
- 资源清单:除CPU以外的全部资源及已经分配到该进程的资源清单
- 链接指针:本进程PCB所在队列中的下一个进程的PCB的首地址
PCB其实就是一个C语言的结构体,这个结构体里存放着一个进程的信息
struct task_struct {// 进程标识符pid_t pid;// 当前进程的状态volatile long state;//打开文件信息struct files_struct *files;//进程的优先级.....
}
一个系统中,通常拥有很多个PCB。常用的组织方法有三种
-
线性方式
所有PCB组织在一张线性表中,存表的首地址,每次扫描整表
-
链接方式
执行指针、就绪队列、阻塞队列、空闲队列等
-
索引方式
根据状态不同,建立索引表(就绪索引表、阻塞索引表
程序是如何运行的
一个进程的实体由PCB、程序段和数据段组成,进程是动态的,进程实体是静态的。进程实体可以反应进程在某一时刻的状态,(如a=10,a++后等于11)
- PCB是给操作系统使用的数据结构
- 程序段和数据段是给进程自己使用的。
比如说我们编写一段C语言程序,先要编译成一个.exe的可执行文件,这个可执行文件是存放在硬盘里面的,在运行这个.exe的可执行程序之前需要把程序放入内存当中。一个程序开始运行前需要为其创建对应的进程,也就是创建对应的PCB。
除了PCB之外,还需一个在内存中开辟一个程序段和数据段。这个程序段就包含了程序要执行的指令,而数据段包含的是程序运行过程中产生的各种数据。
进程是进程实体的运行过程,是操作系统分配资源的最小单位
进程的特征
-
动态性:
动态性是进程最基本的特征,进程是程序的一次执行过程,是动态产生、变化和消亡的。
-
并发性
内存中同时有多个进程实体,各个进程可以并发执行
-
独立性
每个进程都是独立运行互不影响的,独立获得资源、独立接收系统调度
-
异步性
各个进程按各自独立的,不可预知的速度向前推进,也就是说在不考虑资源共享的情况下,各个进程的执行是独立的,操作系统要提供“进程同步机制”来解决一步问题,异步性会导致并发程序的执行结果具有不确定性。
-
结构性
每个进程都会配置一个PCB,结构上看,进程由程序段、数据段、PCB组成
进程的状态和状态转换
-
创建态
一个进程被创建出来,操作系统会为进程分配资源,初始化PCB,此时进程处于创建态
-
就绪态
当进程创建完成后,就会进入就绪态,处于就绪态的进程就已经具备了运行条件了,但由于没有空闲CPU,就暂时不能运行,处于就绪态的进程获得了除CPU以外的所有资源
-
运行态
当CPU空闲时,操作系统就会从就绪队列中选择一个处于就绪态的进程让它上CPU上运行,此时这个真正运行的进程的状态就是运行态,CPU会执行该进程对应的程序(执行指令),此时进程占有了CPU在内的全部资源,在单核CPU的情况下同一时刻最多只能有一个进程处于运行态。
-
阻塞态
在进程运行的过程中,可能会请求等待某个事件的发生(如等待某种系统资源的分配,或者等待其它进程的响应)。在这个事件发生之前,进程无法继续往下执行,此时操作系统会让这个进程下CPU,并让它进入阻塞态
比如说打印机正在为别的进程服务,此时另外一个进程2也想使用打印机,因为此时打印机正在为别的进程服务没空处理这个进程的请求,为了不让进程2占用CPU资源,此时就会让这个进程2进入阻塞态。
此时CPU处于空闲状态的话,操作系统就又会从内存中选择一个处于就绪态的进程上CPU行执行。
等使用打印机的进程结束了,此时打印机资源就空闲下来,此时操作系统就会将打印机资源分配给进程2,此时进程2等待事件就已经发生了,此时就把进程2从阻塞态变成就绪态
-
终止态
假设当进程1运行结束的时候,它会发出一个exit的系统调用,请求操作系统终止该进程,此时该进程就会进入终止态,操作系统会让该进程下CPU,并回收内存空间等资源,最后还有回收改进程的PCB,PCB消失说明进程已经彻底消失了。
五态模型
- 阻塞态—>就绪态,是一种被动行为
- 运行态—>阻塞态是一种进程自身做出的主动行为
需要注意的是,不能由阻塞态直接转换为运行态,也不能由就绪态直接装换为阻塞态。因为进入阻塞态是进程主动请求的,必然需要进程在运行时才能发出请求
进程控制
进程控制的主要功能是对系统中的所有进程控制实施有效的管理,它具有创建新进程、撤销已有进程、进程状态转换等功能。进程控制就是实现进程状态转换。
通过原语就能实现进程控制,原语的执行具有原子性,是不能不打断的。
进程状态装换为啥需要保证原子性
为啥进程控制(状态装换)的过程需要保证原子性?
假设PCB6此时处于阻塞队列如下图,如果此PCB6的等待事件发生,那么负责进程控制的内核程序至少要做这样两件事。
- 将PCB6的状态修改为1
- 将PCB6从阻塞队列放入就绪队列
那么如果执行完第一步的时候,此时CPU收到了一个中断信号,此时的PCB6的state=1,确处于阻塞队列显然不合理,可能会影响操作系统后续的一些操作。
如何实现原语的原子性?
原语的执行具有原子性,也就是执行过程中不允许被中中断。可以使用**“开中断”和“关中断”指令,这两个特权指令实现原子性**。
正常情况:cpu每执行完一条指令都会例行检查是否有中断信号需要处理,如果有
则暂停运行当前这段程序,转而执行相应的中断处理程序。
CPU如果执行了关中断指令,就不在和以前一样,每执行一条指令都会检查是否有中断信号需要处理,而是直接继续往下执行对应的指令,直到执行开中断指令才会恢复检查中断信号,再执行中断处理程序。
为啥开中断关中断这两特权指令允许用户使用会发送什么?
如果开关中断可以给用户使用的话,那么用户只需在程序运行开始执行一条开中断指令,在应用程序结束前才执行开中断,那么这个用户的应用程序就会一直在CPU上运行。
进程控制相关原语
进程创建
创建原语
- 申请空白PCB:获得唯一标识pid
- 为新进程分配所需资源:为新进程的程序和数据以及用户栈分配必要的内存空间
- 初始化PCB:设置进程的状态、设置进程属性、初始化寄存器和上下文等
- 将PCB插入就绪队列
引起进程创建的事件
- 用户登录:分时系统中,用户登录成功,系统会为其建立一个新的进程
- 作业调度:多道批处理系统中,有新的作用放入内存时,会为其建立一个新的进程
- 提供服务:用户向操作系统提出某些请求时,会创建新的进程处理请求
- 应用请求:用用户进程主动请求创建一个子进程
进程终止
撤销原语
撤销原语可以让进程从就绪态/阻塞态/运行态直接变成终止态
- 从PCB集合中找到终止进程的PCB
- 若进程正在运行,立即剥夺CPU,将CPU分配给其它进程
- 终止其所有子进程
- 将该进程拥有的所有资源归还给父进程或操作系统
- 删除PCB
引起进程终止的事件
- 正常结束(进程自己请求终止,exit系统调用)
- 异常结束(整数除以0,非法使用特权指令被操作系统强行杀死)
- 外界干预(在Linux中kill掉一个进程)
进程的阻塞和唤醒
阻塞原语和唤醒原语必须是成对使用的
进程的阻塞
阻塞原语
- 找到阻塞的进程对应的PCB
- 保护进程运行现场,将PCB状态信息设置为“阻塞态”,暂停停止进程运行
- 将PCB插入相应事件的等待队列
引起进程阻塞的事假
- 需要等待系统分配某种资源
- 需要等待相互合作的其他进程完成工作
进程的唤醒
唤醒原语
- 在事件等待队列中找到PCB
- 将PCB从等待队列中移除,设置进程为就绪态
- 将PCB插入到就绪队列,等待被调度
引起进程唤醒的事件
- 等待事件的发生(因何事阻塞,就应由何事唤醒)
进程的切换
切换原语
- 将运行环境(进程上下文)信息存入PCB,包括程序计数器和其它寄存器信息。
- PCB移入相应队列
- 选择另一个进程执行,并更新PCB
- 根据PCB恢复新进程所需要的运行环境
引起进程切换的事件
- 当前进程时间片到
- 有更高优先级的进程到达
- 当前进主动阻塞
- 当前进程终止
进程切换的过程
- 保存处理机上下文,包括程序计数器和其他寄存器
- 更新PCB信息。
- 把进程的PCB移入相应的队列,如就绪、在某事件阻塞等队列
- 选择另一个进程执行,并更新其PCB
- 更新内存管理的数据结构
程序是如何执行的?
- PSW:记录当前程序状态
- PC:程序计数器,记录下一条要执行的指令
假设执行完指令2后,另外一个进要上CPU上执行,也要使用这些寄存器,就可以把一些像PSW、PC、IR,通用寄存器这些必要的信息保存到PCB当中,再让新的进程调度到CPU上执行。
进程通信
进程间通信是指两个进程之间产生数据交互,比如说王者荣耀登录时需要调用QQ或者微信进行登录,这就涉及到进程间的通信。
进程间的通信为什么需要操作系统的支持?
进程是操作系统分配资源的最小单位,因此各进程拥有的内存地址空间是相互独立的,也就是说进程A不能直接访问进程B的地址空间,这属于内存越界访问,如果进程A只可以直接访问进程B的地址空间的话,那么进程B的数据可能就会被进程A给破坏,又或者说进程A把进程B的隐式数据给直接读取走。
共享存储
基于存储区共享
共享存储的进程通信方式指的是,一个进程可以在内存中开辟一块内存空间共享存储区,这个共享存储区可以被其它进程给共享。假设进程A要给进程B发送数据,那么进程A就可以把要发送的数据写入到共享存储区,进程B再从这个共享存储区读取数据。需要注意的是为了避免出错,各个进程对共享空间的访问应该是互斥的。基于存储区的共享是操作系统在内存中划出一块共享存储区,数据的形式、存放位置都由通信进程控制,而不是操作系统。这种共享方式速度很快,是一种高级通信方式。这种通信方式自由度高,开辟出来的共享存储区,想怎么分配数据怎么存都有进程自己决定。
基于数据结构共享
基于数据结构的共享:比如共享空间里只能放个长度为10的数组。这种共享方式速度慢、限制多,是一种低级通信方式。而这种通信方式自由度比较低,就比如是一个Int数组的结果,存储或者读取数据只能以Int为单位。
消息传递
直接通信方式
进程间的数据交换以格式化的消息 (Message)为单位。进程通过操作系统提供的“发送消息/接收消息”两个原语进行数据交换。这种指明接收进程ID的消息传递方式,叫做直接通信方式
进程A通过发送原语send发送消息给进程B,这个发送原语会让操作系统接收到这个消息,就会将这个进程A的msg复制到进程B的PCB中的消息队列里。
然后进程B通过接收原语receive指定接收进程A的消息,那么就会从操作系统内核中的进程B的PCB中的消息队列中将进程A发送过来的msg拿到进程B的地址空间中。
间接通信方式
间接通信方式通过“信箱”间接地通信,因此又称为“信箱通信方式”。通过信箱的方式间接的获取到另外一个进程的消息。
进程A通过系统调用向操作系统申请一个或者多个信箱,通过发送原语把msg发送到信箱Q里面。
然后进程B通过接收原语,从指定从信箱Q中接收消息,从而获得msg。
通常来说操作系统是可以允许多个进程往同一个信箱send消息,也可以多个进程从同一个信箱中receive消息。
管道通信
管道通信和水管类似,只能从一边写数据或者从一边读数据,不能同时写数据和读数据,这种也被称之为半双工。
“管道”是一个特殊的共享文件,又名pipe文件,其实就是某一个进程通过系统调用的方式来申请一个管道文件,操作系统会新建这个管道文件,这个文件的本质在内存中开辟一个大小固定的内存缓冲区,然后两个进程可以进程写数据和读数据,这些数据是先进先出的。
管道通信和共享存储的区别:
共享存储通信开辟的空间想往哪写就往哪写,想从哪读就往哪读。
而管道通信只能安照指定的顺序写数据,同时按照指定的方式读数据。其实管道底层使用循环队列这种数据结构实现的。
- 管道只能采用半双工通信,如果要实现全双工通信就需要向操作系统申请两个管道文件
- 各个进程要互斥地访问管道(由操作系统实现)
- 当管道写满时,写进程将会阻塞,直到读进程将管道中的数据取走,即可唤醒进程
- 当管道为空时,读进程将阻塞,直到写进程往管道中写入数据,即可唤醒读进程。
- 管道中的数据一但被读出就彻底消失,因此当多个进程读同一个管道时,可能会错乱。对此,通常有两种解决方案:
- 一个管道允许多个写进程,一个读进程(考试?)
- 允许有多个写进程,多个读进程,但系统会让各个读进程轮流从管道中读数据 (Linux的方案)
线程概念
在很久以前没有引入进程时,系统中各个程序只能串行执行。也就是我们不能边听音乐边写代码以及QQ聊天。
但是引入进程之后,我们可以边听音乐边写代码,还可以边听音乐边用QQ聊天。但QQ不仅可以聊天,还可以进行视频和传输文件,进程是程序的一次执行,但这些功能显然不可能是由一个进程顺序处理就能实现的。
有的进程可能需要"同时"做很多事情,而传统的进程只能串行的执行一系列程序,因此引入了**“线程”,来增加并发度**。
传统的进程是程序执行流的最小单位,但引入了线程之后,CPU的调度服务对象就不再是进程,而是进程当中的线程,那么线程就成为了程序执行流的最小单位。
为啥要引入线程
可以把线程理解成为**“轻量级进程”,线程是一个基本的CPU执行单元**,也是程序执行流的最小单位。
引入线程之后,不仅是进程之间可以并发,进程内的各线程之间也可以并发,从而进一步提升了系统的并发度,使得一个进程内也可以并发处理各种任务 (如QQ视频、文字聊天、传文件)。
引入线程后,进程只作为除CPU之外的系统资源的分配单元(如打印机、内存地址空间等都是分配给进程的),这些资源都是分配个进程对的而不是线程的。
传统的进程之间并发,需要切换进程的运行环境,系统开销很大。因为进程之间的切换需要保存和恢复整个进程的上下文,开销较大。而线程是在进程内进行调度和切换的基本单位,线程切换的开销较小,因为线程共享进程的上下文。
线程之间的并发,如果是同一进程内的线程切换,则不需要切换进程环境,系统开销小。
引入线程后,并发所带来的系统开销减小。
线程的属性
线程是处理机调度的单位
多CPU计算机中,各个线程可占用不同的CPU
每个线程都有一个线程ID、线程控制块 (TCB)
线程也有就绪、阻塞、运行三种基本状态
线程几乎不拥有系统资源
同一进程的不同线程间共享进程的资源
由于共享内存地址空间,同一进程中的线程间通信甚至无需系统干预
同一进程中的线程切换,不会引起进程切换
不同进程中的线程切换,会引起进程切换
切换同进程内的线程,系统开销很小
切换进程,系统开销很大。
线程的实现方式
用户级线程
早期的操作系统(如早期的unix)只执行进程,不支持线程,当时的"线程"是由线程库来实现的。
假设下面这段伪代码就是一个简单的线程库,QQ要处理视频、聊天和问文件传输。
//伪代码
int main()
{int flag = 0;while (true) {if (flag == 0){// 处理视频聊天代码}else if(flag == 1){// 处理问题聊天的代码}else if (flag == 2){// 处理文件传输的代码}flag = (flag+1)%3;}return 0;
}
假设下图是早期操作系统来实现QQ进程,QQ的多线程是通过线程库来实现的,线程库完成了对线程的管理工作,比如说线程调度。很多编程语言提供了强大的线程库,可以时间线程的创建、销毁、调度等功能。
需要注意的这里的用户线程,是程序员写的一个线程库,创建的是逻辑上的线程。
所以,用户级线程的管理是通过应用程序来通过线程库来完成的,线程的切换也不需要从用户态到内核态的切换,由线程库在用户态来完成。当然操作系统也是看不到这3个逻辑线程的存在的,操作系统只能看到这个进程的存在,进程中有一堆代码。
- 用户级线程由应用程序通过线程库实现所有的线程管理工作都由应用程序负责 (包括线程切换)
- 用户级线程中,线程切换可以在用户态下即可完成,无需操作系统干预。
- 在用户看来,是有多个线程。但是在操作系统内核看来,并意识不到线程的存在。
“用户级线程”就是“从用户视角看能看到的线程
优缺点
- 优点:用户级线程的切换在用户空间即可完成,不需要切换到核心态,线程管理的系统开销小,效率高
- 缺点:当一个用户级线程被阻塞后,整个进程都会被阻塞,并发度不高。多个线程不可
在多核处理机上并行运行。
内核级线程
内核级线程又叫**“内核支持的线程”**
- 内核级线程的管理工作由操作系统内核完成。
- 线程调度、切换等工作都由内核负责,因此内核级线程的切换必然需要在核心态下才能完成。
- 操作系统会为每个内核级线程建立相应的TCB (Thread Control Block,线程控制块)
通过TCB对线程进行管理。“内核级线程”就是“从操作系统内核视角看能看到的线程
优缺点
- 优点:当一个线程被阻塞后,别的线程还可以继续执行,并发能力强。多线程可在多核
处理机上并行执行。 - 缺点:一个用户进程会占用多个内核级线程线程切换由操作系统内核完成,需要切换到核心态,因此线程管理的成本高,开销大。
多线程模型
一对一模型
一对一模型:一个用户级线程映射到一个内核级线程。每个用户进程有与用户级线程同
数量的内核级线程。
- 优点:当一个线程被阻塞后,别的线程还可以继续执行,并发能力强。多线程可在多核处理机上并行执行。
- 缺点:
一个用户进程会占用多个内核级线程线程切换由操作系统内核完成,需要切换到核心态,因此线程管理的成本高,开销大。
多对一模型
多对一模型:多个用户级线程映射到一个内核级线程。且一个进程只被分配一个内核级
线程。
-
优点:用户级线程的切换在用户空间即可完成,不需要切换到核心态,线程管理的系统开销小,效率高
-
缺点:当一个用户级线程被阻塞后,整个进程都会被阻塞,并发度不高。多个线程不可在多核处理机上并行运行
操作系统只“看得见”内核级线程,因此只有内核级线程才是处理机分配的单位。
多对多模型
在支持内核级线程的系统中,根据用户级线程和内核级线程的映射关
系,可以划分为几种多线程模型。
多对多模型:n用户及线程映射到m个内核级线程(n >= m)。每个用户进程对应m 个内核
级线程。克服了多对一模型并发度不高的缺点 (一个阻塞全体阻塞),又克服了一对一模型中一个用户进程占用太多内核级线程,开销太大的缺点
可以这么理解:
用户级线程是“代码逻辑”的载体内核级线程是“运行机会”的载体。
内核级线程才是处理机分配的单位,列如:多核CPU环境下,上图这个进程最多能被分配两个核。
一段“代码逻辑”只有获得了“运行机会”才能被CPU执行内核级线程中可以运行任意一个有映射关系的用户级线程代码,只有两个内核级线程中正在运行的代码逻辑都阻塞时,这个进程十会阻塞。
线程的状态和转换
线程的状态的装换和进程的状态转换完全一致,并且线程的状态我们只是关注最核心的三个状态,运行、阻塞、就绪。
线程的组织与控制
线程的控制通过**线程控制块(TCB)**完成,TCB中包含以下主要字段
- 线程标识符TID和PID类似
- 程序计数器PC:线程目前执行到哪里了
- 如果一个线程下CPU变成就绪或者阻塞状态,就需要把CPU中PC的值保存到程序计数器PC当中
- 如果一个线程又要上PCB上运行,就要恢复线程的运行现场和运行环境,就可以从TCB上取出PC放到PC寄存器里
- 其它寄存器:线程运行的中间结果,同理进行线程切换是需要保存中间的一些结果,就是将一些其它寄存器里的值保存到TCB中
- 堆栈指针:堆栈保存函数调用信息,局部变量等,比如说A函数掉用了B函数就会被记录到堆栈中
- 用于存储线程的局部变量、函数调用信息和临时数据。
- 比如说A调用B、B再调用C,并且会记录每次函数调用的返回地址是什么
- 同时每个函数的局部变量也会放到堆栈里
- 线程的堆栈是比较大的,全部放到堆栈指针里是没有必要的,只需要保存堆栈定指针
- 线程运行状态:运行/就绪/阻塞
- 优先级:线程的调度、资源分配的参考
程序计数器PC、其它寄存器、堆栈指针都是线程切换需要保存恢复的
通过线程表可以将多个TCB进行组织,可没一个进程有一张TCB线性表,又或者根据线程的状态组织一张线性表,不同的操作系统实现方式不同。
进程和线程的区别
- 进程是操作系统分配资源的基本单位
- 线程是程序执行的基本单位
- 进程是包含线程的,一个进程可以包含一个或者多个线程
- 进程拥有内存空间和文件资源,而线程共享进程的内存和文件资源
- 进程之间的通信需要操作系统参与,而线程之间可以直接共享
- 进程的切换开销比较到,需要保存上下文和状态,而线程的切换代价比较小,因为它们共享进程的资源。
- 当两个线程是属于同一个进程,因为虚拟内存是共享的,所以在切换时,虚拟内存这些资源就保持不动,只需要切换线程的私有数据、寄存器等不共享的数据;