进程和线程的区别和联系
Posted 小鱼不会骑车
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了进程和线程的区别和联系相关的知识,希望对你有一定的参考价值。
进程和线程的区别和联系
1. 认识线程
线程是进程的一个实体,它被包含在进程中,一个进程至少包含一个线程,一个进程也可以包含多个线程,线程是CPU调度和分派的基本单位,他是比进程更小的能独立运行的基本单位,线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),一个线程可以创建和撤销另一个线程.
网络上有一个图片是这样描述进程与线程的:
为什么会有线程的存在:
早在80年代,由于进程的创建和销毁以及切换存在较大的空间开销,因此人们急需一种轻型的进程技术来减少资源的开销.于是便线程的概念便但诞生了.线程被设计成进程的一个执行路径,同一个进程中的线程共享进程资源.因此系统对于线程的调度远远小于进程.
虽然说线程之间的切换开销小,但是由于多个线程共享同一个进程的资源,所以如果一个线程崩溃,那么就可能导致整个进程被系统抹杀.但是进程不用担心,每个进程都有独立的代码和数据空间(程序上下文),即使这个进程崩了也不会影响到其他的进程,就类似于我QQ崩了跟我微信有什么关系.
大家通过上述的图片也可以看见,一个进程中包含多个线程,通俗点理解的话就是,我的B站,可以一边看视频,一边投币,顺便再点个收藏这些都是由不同的线程来完成的任务.所以这里就体现了进程和线程的包含关系.
2. 进程和线程的关系
(1)一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。
(2)资源分配给进程,同一进程的所有线程共享该进程的所有资源。
(3)线程在执行过程中,需要协作同步。不同进程的线程间要利用消息通信的办法实现同步。
(4)处理机分给线程,即真正在处理机上运行的是线程。
(5)线程是指进程内的一个执行单元,也是进程内的可调度实体。
3. 进程和线程的区别
- 本质区别: 进程是操作系统进行资源分配的基本单位,线程是独立调度和分派的基本单位。
- 包含关系: 如果一个进程内有多个线程,则执行过程并不是一条直线,而是多条线(线程)共同完成的.线程是进程的一部分,所以线程也被称为轻量级进程或轻权进程.
- 资源开销: 每个进程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销:线程可以看作轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器,线程之间切换的开销小.
- 进程和线程的创建和销毁: 假如我要创建一个进程,我先要遍历我的内存资源找到一块合适的内存再分配给它,当我要销毁一个进程时,还是要先遍历我的内存资源,找到我的进程才能对其进行销毁.但是如果是创建一个线程,我们可以认为该进程是一个酒店,当我想创建一个线程时,直接开一个房间就好了,销毁线程时直接退房,此时可以看出,进程的创建和销毁在资源分配上浪费了很多时间,但是线程的创建和销毁则不需要那么麻烦.
- 内存分配: 同一个进程的线程共享本进程的地址空间和资源,而进程之间的地址空间和资源是相互独立的.
- 影响关系: 一个进程崩溃后,在保护模式下并不会对其他进程产生影响,但是一个线程崩溃,可能会导致包含该线程的整个进程都直接死掉.所以多进程要比多线程健壮.
- .操纵者不同:进程的操纵者一般是操作系统,线程的操纵者一般是编程人员。
- 执行过程:每个独立的进程有程序运行的入口、顺序执行序列和程序出口。但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制,两者均可并发执行.
4. 线程共享了进程哪些资源
再了解该知识点时,我们先了解一下什么是上下文切换.
1. 上下文切换
这里小鱼画了一个简易的进程和线程的关系图
为了便于更好的理解我给大家优化一下上述的图:
我们可以将整个进程看成一个工厂,为生产活动体提供了设计图,场地,流水线(线程)等生产要素,而线程呢?我们就可以理解为是这个工厂的一个个流水线,流水线本身会有一个操作台,具体的零件在这里被生产,由于生产线需要由工人来操作才能开始执行,但是由于这个工人并不知道该零件加工到了哪一部分,所以需要通过查阅该流水线的生产记录才可以弄清这个流水线的零件加工到那种程度,才能为接下来的后续加工提供保障,并且,当工人停止这次流水线的执行之后,也需要记录这次的生产进度,以备下次读取,这些生产进度可以理解为上下文,读生产记录和写生产记录的过程称为上下文切换.
2. 线程共享了进程哪些资源
我们知道了进程和线程的本质区别是:
进程是操作系统进行资源分配的基本单位,线程是独立调度和分派的基本单位.线程之间共享着进程的资源.
但是我们真的理解这句话的含义吗?
下面就为您解答:
线程私有资源
函数运行时的信息保存在栈帧中,栈帧中保存了函数的返回值、调用其它函数的参数、该函数使用的局部变量以及该函数使用的寄存器信息,如图所示,假设函数A调用函数B:
此外,CPU 执行指令的信息保存在一个叫做程序计数器的寄存器中,通过这个寄存器我们就知道接下来要执行哪一条指令。由于操作系统随时可以暂停线程的运行,因此我们保存以及恢复程序计数器中的值就能知道线程是从哪里暂停的以及该从哪里继续运行了。
由于线程运行的本质就是函数运行,函数运行时信息是保存在栈帧中的,因此每个线程都有自己独立的、私有的栈区。
同时函数运行时需要额外的寄存器来保存一些信息,像部分局部变量之类。这些寄存器也是线程私有的,一个线程不可能访问到另一个线程的这类寄存器信息。
从上面的讨论中我们知道,到目前为止,所属线程的栈区、程序计数器、栈指针以及函数运行使用的寄存器是线程私有的.
以上这些信息有一个统一的名字,就是线程上下文,thread context。
我们也说过操作系统调度线程需要随时中断线程的运行并且需要线程被暂停后可以继续运行,操作系统之所以能实现这一点,依靠的就是线程上下文信息。
此时我们已经知道了哪些资源是线程私有的。除此之外,剩下的都是线程间共享资源。那么剩下的还有什么呢?还有图中的这些。
这其实就是进程地址空间的样子,也就是说线程共享进程地址空间中除线程上下文信息中的所有内容,意思就是说线程可以直接读取这些内容。
接下来我们分别来看一下这些区域。
1.代码区
进程地址空间中的代码区,这里保存的是什么呢?从名字中有的同学可能已经猜到了,没错,这里保存的就是我们写的代码,更准确的是编译后的可执行机器指令。
那么这些机器指令又是从哪里来的呢?答案是从可执行文件中加载到内存的,可执行程序中的代码区就是用来初始化进程地址空间中的代码区的。
线程之间共享代码区,这就意味着程序中的任何一个函数都可以放到线程中去执行,不存在某个函数只能被特定线程执行的情况。
2. 数据区
进程地址空间中的数据区,这里存放的就是所谓的全局变量/成员变量。
什么是成员变量?(在方法外定义的遍历就是成员变量)
3. 堆区
堆区是程序员比较熟悉的,我们在 java中new 出来的数据就存放在这个区域,很显然,只要知道变量的地址,也就是引用,任何一个线程都可以访问引用指向的数据,因此堆区也是线程共享的属于进程的资源。
[转帖]进程线程和协程之间的区别和联系
进程、线程和协程之间的区别和联系
https://blog.csdn.net/daaikuaichuan/article/details/82951084
原创lx青萍之末 发布于2018-10-06 14:56:24 阅读数 12560 收藏
展开
文章目录
一、进程
二、线程
三、进程和线程的区别与联系
四、一个形象的例子解释进程和线程的区别
五、进程/线程之间的亲缘性
六、协程
一、进程
进程,直观点说,保存在硬盘上的程序运行以后,会在内存空间里形成一个独立的内存体,这个内存体有自己独立的地址空间,有自己的堆,上级挂靠单位是操作系统。操作系统会以进程为单位,分配系统资源(CPU时间片、内存等资源),进程是资源分配的最小单位。
【进程间通信(IPC)】:
管道(Pipe)、命名管道(FIFO)、消息队列(Message Queue) 、信号量(Semaphore) 、共享内存(Shared Memory);套接字(Socket)。
二、线程
线程,有时被称为轻量级进程(Lightweight Process,LWP),是操作系统调度(CPU调度)执行的最小单位。
三、进程和线程的区别与联系
【区别】:
调度:线程作为调度和分配的基本单位,进程作为拥有资源的基本单位;
并发性:不仅进程之间可以并发执行,同一个进程的多个线程之间也可并发执行;
拥有资源:进程是拥有资源的一个独立单位,线程不拥有系统资源,但可以访问隶属于进程的资源。进程所维护的是程序所包含的资源(静态资源), 如:地址空间,打开的文件句柄集,文件系统状态,信号处理handler等;线程所维护的运行相关的资源(动态资源),如:运行栈,调度相关的控制信息,待处理的信号集等;
系统开销:在创建或撤消进程时,由于系统都要为之分配和回收资源,导致系统的开销明显大于创建或撤消线程时的开销。但是进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个进程死掉就等于所有的线程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。
【联系】:
一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程;
资源分配给进程,同一进程的所有线程共享该进程的所有资源;
处理机分给线程,即真正在处理机上运行的是线程;
线程在执行过程中,需要协作同步。不同进程的线程间要利用消息通信的办法实现同步。
四、一个形象的例子解释进程和线程的区别
这副图是一个双向多车道的道路图,假如我们把整条道路看成是一个“进程”的话,那么图中由白色虚线分隔开来的各个车道就是进程中的各个“线程”了。
这些线程(车道)共享了进程(道路)的公共资源(土地资源)。
这些线程(车道)必须依赖于进程(道路),也就是说,线程不能脱离于进程而存在(就像离开了道路,车道也就没有意义了)。
这些线程(车道)之间可以并发执行(各个车道你走你的,我走我的),也可以互相同步(某些车道在交通灯亮时禁止继续前行或转弯,必须等待其它车道的车辆通行完毕)。
这些线程(车道)之间依靠代码逻辑(交通灯)来控制运行,一旦代码逻辑控制有误(死锁,多个线程同时竞争唯一资源),那么线程将陷入混乱,无序之中。
这些线程(车道)之间谁先运行是未知的,只有在线程刚好被分配到CPU时间片(交通灯变化)的那一刻才能知道。
五、进程/线程之间的亲缘性
亲缘性的意思是进程/线程只在某个cpu上运行(多核系统),比如:
BOOL WINAPI SetProcessAffinityMask(
_In_ HANDLE hProcess,
_In_ DWORD_PTR dwProcessAffinityMask
);
/*
dwProcessAffinityMask 如果是 0 , 代表当前进程只在cpu0 上工作;
如果是 0x03 , 转为2进制是 00000011 . 代表只在 cpu0 或 cpu1上工作;
*/
使用CPU亲缘性的好处:设置CPU亲缘性是为了防止进程/线程在CPU的核上频繁切换,从而避免因切换带来的CPU的L1/L2 cache失效,cache失效会降低程序的性能。
六、协程
协程,是一种比线程更加轻量级的存在,协程不是被操作系统内核所管理,而完全是由程序所控制(也就是在用户态执行)。这样带来的好处就是性能得到了很大的提升,不会像线程切换那样消耗资源。
子程序,或者称为函数,在所有语言中都是层级调用,比如A调用B,B在执行过程中又调用了C,C执行完毕返回,B执行完毕返回,最后是A执行完毕。所以子程序调用是通过栈实现的,一个线程就是执行一个子程序。子程序调用总是一个入口,一次返回,调用顺序是明确的。而协程的调用和子程序不同。
协程在子程序内部是可中断的,然后转而执行别的子程序,在适当的时候再返回来接着执行。
def A():
print ‘1‘
print ‘2‘
print ‘3‘
def B():
print ‘x‘
print ‘y‘
print ‘z‘
假设由协程执行,在执行A的过程中,可以随时中断,去执行B,B也可能在执行过程中中断再去执行A,结果可能是:1 2 x y 3 z。
协程的特点在于是一个线程执行,那和多线程比,协程有何优势?
极高的执行效率:因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显;
不需要多线程的锁机制:因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。
参考:https://blog.csdn.net/tennysonsky/article/details/46046317
https://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/0013868328689835ecd883d910145dfa8227b539725e5ed000
https://www.cnblogs.com/work115/p/5620272.html
https://blog.csdn.net/liu251890347/article/details/38509943
https://www.cnblogs.com/fah936861121/articles/8043187.html
http://blog.chinaunix.net/uid-25601623-id-5095687.html
————————————————
版权声明:本文为CSDN博主「lx青萍之末」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/daaikuaichuan/article/details/82951084
以上是关于进程和线程的区别和联系的主要内容,如果未能解决你的问题,请参考以下文章