进程和线程的区别、多线程和多进程的区别、为什么要引入多线程
进程和线程的区别
(1) 线程是轻量级的进程,它的创建和销毁、上下文切换所需要的时间比进程小得多。
(2) 线程作为调度的基本单位,处理机分给线程,即真正在处理机上运行的是线程。而进程是系统资源分配的最小单位。
(3) 线程依赖于进程而存在,一个线程只能属于一个进程,一个进程可以有一个线程或者多个线程。
(4) 进程有独立的地址空间,同一进程下的各个线程之间共享进程的地址空间(包括代码段、数据集、堆等)及一些进程级的资源(如打开文件和信号),某进程内的线程在其它进程不可见。
(5) 进程结束后,该进程下的所有线程将销毁,而一个线程的结束不会影响同一进程下的其他线程。
多线程和多进程的区别
每个线程类似于独立的进程,只有一点区别:它们共享地址空间,从而能够访问相同的数据。
与进程相比,线程之间的上下文切换有一点主要区别:地址空间保持不变(即不需要切换当前使用的页表)。
为什么要引入多线程?
下面举一个例子,来说明引入多线程的好处。
假设用户正在写一本书。从作者的观点来看,最容易的方法是把整本书作为一个文件,这样一来,查询内容、完成全局替换等都非常容易。另一种方法是,把每一章都处理成单独一个文件。但是,在把每个小节和子小节都分成单个的文件之后,若必须对全书进行全局的修改时,那就真是麻烦了,因为有成百个文件必须一个个地编辑。例如,如果所建议的某个标准××××正好在书复印之前被批准了,于是“标准草案××××”一类的字眼就必须改为“标准××××”。如果整本书是一个文件,那么只要一个命令就可以完成全部的替换处理。相反,如果一本书分成了300个文件,那么就必须分别对每个文件进行编辑。
现在考虑,如果有一个用户突然在一个有800页的文件的第一页上删掉了一段话之后,会发生什么情形。在检查了所修改的页面并确认正确后,这个用户现在打算接着在第600页上进行另一个修改,并键入一条命令通知字处理软件转到该页面(可能要查阅只在那里出现的一个短语)。于是字处理软件被强制对整本书的前600页重新进行格式化处理,这是因为在排列该页前面的所有页面之前,字处理软件并不知道第600页的第一行应该在哪里。而在第600页的页面可以真正在屏幕上显示出来之前,计算机可能要拖延相当一段时间,从而令用户不甚满意。
多线程在这里可以发挥作用。假设字处理软件被编写成含有两个线程的程序。一个线程与用户交互,而另一个在后台重新进行格式处理。一旦在第1页中的语句被删除掉,交互线程就立即通知格式化线程对整本书重新进行处理。同时,交互线程继续监控键盘和鼠标,并响应诸如滚动第1页之类的简单命令,此刻,另一个线程正在后台疯狂地运算。如果有点运气的话,重新格式化会在用户请求查看第600页之前完成,这样,第600页页面就立即可以在屏幕上显示出来。
如果已经做到了这一步,那么为什么不再进一步增加一个线程呢?许多字处理软件都有每隔若干分钟自动在磁盘上保存整个文件的特点,用于避免由于程序崩溃、系统崩溃或电源故障而造成用户一整天的工作丢失的情况。第三个线程可以处理磁盘备份,而不必干扰其他两个线程。拥有三个线程的情形,如图2-7所示。
如果程序是单线程的,那么在进行磁盘备份时,来自键盘和鼠标的命令就会被忽略,直到备份工作完成为止。用户当然会认为性能很差。另一个方法是,为了获得好的性能,可以让键盘和鼠标事件中断磁盘备份,但这样却引入了复杂的中断驱动程序设计模型。如果使用三个线程,程序设计模型就很简单了。第一个线程只是和用户交互;第二个线程在得到通知时进行文档的重新格式化;第三个线程周期性地将RAM中的内容写到磁盘上。
很显然,在这里用三个不同的进程是不能工作的,这是因为三个线程都需要对同一个文件进行操作。由于多个线程可以共享公共内存,所以通过用三个线程替换三个进程,使得它们可以访问同一个正在编辑的文件,而三个进程是做不到的。
许多其他的交互式程序中也存在类似的情形。例如,电子表格是允许用户维护矩阵的一种程序,矩阵中的一些元素是用户提供的数据;另一些元素是通过所输入的数据运用可能比较复杂的公式而得出的计算结果。当用户改变一个元素时,许多其他元素就必须重新计算。通过一个后台线程进行重新计算的方式,交互式线程就能够在进行计算的时候,让用户从事更多的工作。类似地,第三个线程可以在磁盘上进行周期性的备份工作。
例子来源:《现代操作系统(第四版)》Andrew S. Tanenbaum / Herbert Bos