1 进程和线程形象解释
首先,《进程与线程的一个简单解释》形象生动地将计算机 CPU 比做一个工厂,进程相当于工厂内不同车间,线程相当于车间内不同协作的工人。
工厂电力有限,一次只能一个车间开工:单个CPU一次只能运行一个进程,其他进程处于非运行状态。
一个车间里可以有很多工人协同工作:一个进程可以包括多个线程协同进行。
车间空间由工人们共享:一个进程的内存空间是每个线程共享的。
车间内每间房间的大小不同,里面人满的时候,其他人就不能进去了:某些线程使用某些共享内存时,若线程数目超出限制,则其他线程必须等其中线程结束,才能使用这一块内存。
为了控制房间不超出人数限制,就在门口挂一定数量的钥匙,进去的人取一把,出来时放回原处,后到的人若取不到钥匙就在门口排队:该做法叫做“信号量”(Semaphore),用来保证多个线程不会互相冲突,即控制多个线程同时读写某一块内存区域。
操作系统的设计可以归纳为三点:
- 以多进程形式,允许多个任务同时运行;
- 以多线程形式,允许单个任务分成不同的部分运行;
- 提供协调机制,一方面防止进程之间和线程之间产生冲突,另一方面允许进程和线程之间共享资源。
2 进程和线程时间维度上的解释
该部分来源于知乎问题“线程和进程的区别是什么?”中的回答
进程和线程都是一个 CPU 工作时间段的描述,颗粒大小不同。
执行一段程序代码,除了CPU以外所有的就构成了这个程序的执行环境,也就是我们所定义的程序上下文。当这个程序执行完了,或者分配给他的CPU执行时间用完了,那它就要被切换出去,在被切换出去的最后一步工作就是保存程序上下文,因为这个是下次他被 CPU 执行的运行环境,必须保存。
在CPU看来所有的任务都是一个一个的轮流执行的,具体的轮流方法就是:先加载程序A的上下文,然后开始执行A,保存程序A的上下文,调入下一个要执行的程序B的程序上下文,然后开始执行B,保存程序B的上下文。
进程就是包换上下文切换的程序执行时间总和 = CPU加载上下文+CPU执行+CPU保存上下文
进程的颗粒度太大,每次都要有上下的调入,保存,调出。如果我们把进程比喻为一个运行在电脑上的软件,那么一个软件的执行不可能是一条逻辑执行的,必定有多个分支和多个程序段,就好比要实现程序A,实际分成 a,b,c等多个块组合而成。
那么这里具体的执行就可能变成:
程序A得到CPU =》CPU加载上下文,开始执行程序A的a小段,然后执行A的b小段,然后再执行A的c小段,最后CPU保存A的上下文。
这里a,b,c的执行是共享了A的上下文,CPU在执行的时候没有进行上下文切换的。这里的a,b,c就是线程,也就是说线程是共享了进程的上下文环境的、更为细小的CPU时间段
3 进程和线程在操作系统上的解释
该部分来源于《操作系统、进程与线程》 一文:
在操作系统中执行的程序,都以进程的方式运行在更低的权限中。事实上,操作系统是以进程为单位去分配空间和执行的。但是,进程和程序有什么不同呢?
我们说程序是一组指令的集合,它静态存储于诸如磁盘之类的存储器里;
当一个程序被操作系统执行时,它就会被载入内存空间,并在逻辑上产生一个独立的实例,这就是进程。
这就好像是说,程序是一道菜谱,其中的指令,就是指挥你开火加盐的步骤;进程则是烹饪的过程,操作系统按照指令一丝不苟地烹饪,得到的结果就是我们的菜肴。
随着 CPU 频率增长逐渐停滞,CPU 开始向多核的方向发展。为了让多个 CPU 核心同时为我们工作,并行地执行任务,就需要涉及线程的概念。线程的英文是 Thread,有时也称为轻量级进程 (Lightweight Process),它是操作系统进行任务调度的最小单元。线程存活于进程之中;同一个进程中的线程,共享一个虚拟内存空间,以及其中的资源;线程之间各自持有自己的线程 ID、当前指令的指针(PC)、寄存器集合以及栈。
4 进程和线程理论与表述
该部分来源于知乎问题“线程和进程的区别是什么?”中的回答
进程是资源(CPU、内存等)分配的基本单位,具有一定功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。
线程是进程的一个实体,是独立运行和独立调度的基本单位(CPU上真正运行的是线程)。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。
二者的区别:
- 进程是资源分配的基本单位;线程是程序执行的基本单位。
- 进程拥有自己的资源空间,每启动一个进程,系统就会为它分配地址空间;而线程与CPU资源分配无关,多个线程共享同一进程内的资源,使用相同的地址空间。
- 一个进程可以包含若干个线程。
二者优劣比较:
- 线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据,而进程之间的通信需要以通信的方式(Inter Process Communication,IPC)进行。不过如何处理好同步与互斥是编写多线程程序的难点。
- 线程的调度与切换比进程快很多,同时创建一个线程的开销也比进程要小很多。
- 但是多进程程序更健壮,多线程程序只要有一个线程死掉,整个进程也死掉了,而一个进程死掉并不会对另外一个进程造成影响,因为进程有自己独立的地址空间。
口语表述:
进程的本质::正在执行的一个程序,可以进程比作一个容器或者工厂
- 进程与进程之间相对独立
- 进程可以包括几个或者上百个线程在运行。
- 内存(逻辑内存)包括在进程里面,每个进程的内存都是互相独立的,但从一个更高的层次上看,不同的进程也共享着一个巨大的空间,这个空间就是整个计算机。
- 进程共有文件/网络句柄(handle),这样可以打开同一个文件,抢同一个网络端口。
线程的本质:真正运行的是一个一个的线程
线程包含:
- 栈(堆栈):主线程的main函数、进行函数调用的参数和返回地址、局部变量等内容都会被压入栈内
- PC(Program Couner):程序计数器,PC的指针指向代码所在的内存地址。
- TLS(Thread local storage):分配内存,存放变量
通信是人的基本需求,进程与进程之间是相互独立的,也有通信需求。根据这一问题就可以展开内容提问:进程/线程如何通信?
答:进程可以通过管道、套接字、信号交互、共享内存、消息队列等等进行通信;而线程本身就会共享内存,指针指向同一个内容,交互很容易。
一旦有了通信,进程就会产生矛盾。这些矛盾就会体现在如何同步上。在单个CPU下,实际上在任何时刻只能有一个进程处于执行状态。而其他进程则处于非执行状态。我们是如何确定在任意时刻到底由哪个进程执行,哪些不执行呢?(如何进行进程调度?)线程之间的关系是合作关系。既然是合作,那就得有某种约定的规则,否则合作就会出问题。(如何进行线程同步?)
还有内存问题,进程要分配内存,所以开销很大;线程只需要分配栈,分配一个PC(程序计数器)就好,内存开销小。
参考链接
- 《进程与线程的一个简单解释》阮一峰 http://www.ruanyifeng.com/blog/2013/04/processes_and_threads.html
- 知乎问题“线程和进程的区别是什么?”回答https://www.zhihu.com/question/25532384/answer/81152571
- 《程序员的自我修养(二):操作系统、进程与线程》https://liam.page/2017/01/17/layers-and-operation-system/
- 知乎问题“线程和进程的区别是什么?”回答https://www.zhihu.com/question/25532384/answer/1130818664