这篇文章主要是总结我对进程/线程的理解,不是教程。欢迎大家补充和提错。
进程
进程是对正在运行程序的抽象,即使可以使用的cpu只有一个,也可以支持并发(不是并行)操作。进程包含程序计数器,寄存器,当前变量的值等程序运行所需要的资源。
假设现在只有一个物理程序计数器和多个独立运行的程序。每个程序在运行时,它的逻辑计数器被装入实际的物理计数器中,当该程序执行结束(或暂停执行)时,物理程序计数器被保存在内存中该进程的逻辑程序计数器中。科学家做蛋糕的例子,就不再写了,大家可以去搜一下。
进程的创建
由于能力有限,这里只说明在unix系统中的情况。
在UNIX系统中,只有一个系统调用可以用来创建新进程:fork。这个系统调用会创建一个与调用进程 相同的副本。在调用了fork后,这两个进程(父进程和子进程)拥有相同的存储映像、同样的环境字符串和 同样的打开文件。
进程的退出
进程不是永远存在的,进程的终止,通常是由以下条件引起的:1)正常退出(自愿)。2)出错退出(自愿)。3)严重错误(非自愿)。4)被其他进程杀死(非自愿)。
进程的层次结构
在UNIX中,进程和它的所有子女以及后裔共同组成一个进程组。当用户从键盘发出一个信号时,该信号被送给当前与键盘相关的进程组中的所有成员(它们通常是在当前窗口创建的所有活动进程)。每个进程可以分别捕获该信号、忽略该信号或采取默认的动作,即被该信号杀死。
进程的状态
进程拥有三种状态:1)运行态(该时刻进程实际占用cpu)2)就绪态(可运行,但因其他程序正在运行而暂时停止)3)阻塞态(除非进程所需要的某种外部事件发生,否则进程不能运行)
进程的实现
为了实现进程模型,操作系统维护着一张表格(一个结构数组),即进程表(process table)。每个进程占用一个进程表项。(有些作者称这些表项为进程控制块。)该表项包含了进程状态的重要信息,包括程序计数器、堆栈指针、内存分配状况、所打开文件的状态、账号和调度信息,以及其他在进程由运行态转换 到就绪态或阻塞态时必须保存的信息,从而保证该进程随后能再次启动,就像从未被中断过一样。
线程
线程跟进程类似,或者叫轻量级进程,但在同一个进程下的多个线程是共享同一个地址空间和所有可用数据。
为什么需要线程
主要原因是,在许多应用中同时发生着多种活动,其中某些活动会随着时间的推移,发生阻塞。通过把这些应用分解成多个准并行的顺序线程,程序设计模型会变得更简单。
第二个原因,线程比进程更轻量级,创建线程比进程更快。这里的轻量,个人理解重点是因为资源的申请,以及在调度时的开销,因为进程有自己的地址空间,所以在进行进程切换时,页表、cache、TLB中的内容发生变化,原进程保存的内容无效,新的进程必须重新加载,导致缺页中断增多,cache,TLB也命中率下降。而线程切换会保留页表、cache、TLB中的内容,因为多个线程之间共享进程的这部分资源。
第三个原因,可以提高性能。如果存在着大量的计算和大量的I/O处理,拥有多个线程允许这些活动彼此重叠进行,从而会加快应用程序执行的速度。
今天就暂时先到这里了,下一篇写线程模型和实现