进程、线程总结
一、进程
1.概念:进程是程序的一次执行过程,是系统进行资源分配和调度的一个独立单位
2.进程实体(进程映像):由程序段、相关数据段和PCB三部分构成。进程是动态的,进程实体是静态的
3.PCB:进程控制块,系统利用PCB来描述进程的基本情况和运行状态,进而控制和管理进程;所谓创建进程,实际上是创建进程映像中的PCB;
PCB是进程存在的唯一标志
4.进程的状态
进程有5种状态,其中前3种是基本状态。
(1)运行态:进程正在处理机上运行。在单处理机的情况下,任一时刻最多只有一个进程处理运行态。
(2)就绪态:进程已经获得除处理机之外的一切所需资源,一旦得到处理机就可以进入运行态。
(3)阻塞态(等待态):进程正在等待某一事件/某一资源而暂停运行。这时候,即使处理机空闲,该进程也不能进入运行态。
5.进程的创建
创建过程:
(1)分配ID与PCB:为新进程分配一个唯一的进程标识号,并申请一个空白的PCB(PCB是有限的)。若PCB申请失败则创建失败。
(2)分配资源:为新进程的程序和数据、以及用户栈分配必要的内存空间(在PCB 中体现)。注意:这里如果资源不足(比如内存空间),并不是创建失败,而是处于阻塞态。
(3)初始化PCB:主要初始化(1)标志信息(2)处理机状态信息(3)处理机控制信息,以及(4)设置进程的优先级等。
(4)调度:如果进程就绪队列能够接纳新进程,就将新进程插入到就绪队列,等待被调度运行。
注意,进程的创建是一个原子操作,执行期间不允许中断,它是一个不可分割的基本单位。
创建方法:
fork vfork clone函数(具体区别见下文)
6. 进程的终止
引起进程终止的事件主要有:
(1)正常结束
(2)异常结束:如存储区越界、非法指令、I/O故障等
(3)外界干预:如操作员或操作系统干预、父进程请求、父进程终止。
操作系统终止进程的过程如下:
(1)根据被终止进程的ID,检索PCB,从中读出该进程的状态
(2)若被终止进程处于执行状态,立即终止该进程的执行,将处理机资源分配给其他进程
(3)若该进程还有子进程,则应将其所有的子进程终止
(4)将该进程所拥有的资源,或归还给其父进程或归还给操作系统
(5)将该PCB从所在队列(链表)中删除。
7.进程之间的切换
(1)保存处理机上下文,包括程序计数器和其他寄存器。
(2)更新PCB信息。
(3)把进程的PCB移入相应的队列,如就绪、在某事件阻塞等队列。
(4)选择另一个进程执行,并更新其PCB。
(5)更新内存管理的数据结构。
(6)恢复处理机上下文。
注意:“调度”和“切换”的区别:调度是指决定资源分配给哪个进程的行为,是一种决策行为;切换是指实际分配的行为,是执行行为。一般来说,等有资源的调度,再有进程的切换。
8.多进程进程间的通讯方式
(1)管道:半双工;数据只能单向流动,只能用于具有亲缘关系的进程之间,即用于父子、兄弟之间。
(2)命名管道(FIFO):半双工,允许无亲缘关系的进程(3)消息队列:消息链表存于内核,每个消息队列由消息队列标识符标识;于管道不同的是,消息队列存放在内核中,只有在内核重启时才能删除一个消息队列;消息队列的大小受限制。
(4)信号量(semophore):信号量是一个计数器,可以用来控制多个进程对于共享资源的访问。作为一种锁机制,防止某进程正在访问共享资源师,其他进程也访问该资源,常用来处理临界资源的访问同步问题。
临界资源:为某一时刻只能由一个进程或线程操作的资源。
(5)共享内存:就是映射一段能被其他进程所访问的内存,这段内存由一个进程创建,但可以多个进程同时访问,可以说是最有用的进程间通信方式,也是最快的IPC形式。 常与其他通讯机制(信号量)配合使用。(6)套接字:也可用于不同机器之间。
(7)信号(Signal):比较复杂,用于通知接收进程某个事件已经发生
二、线程
1.概念:线程是轻量化的进程,是程序执行流的最小单位;由线程ID、程序计数器、寄存器集合和堆栈组成;线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其他线程共享进程所拥有的全部资源。
2.线程独有的内容:
线程上下文 包括:线程ID 、栈、栈指针、PC(程序计数器)、通用目的寄存器、条件码
3.线程共享的内容:
文件描述符和整个用户虚拟地址空间,包括:只读文本(代码)、静态变量、堆、所有的共享库代码和数据区域组成。
4.分离线程
线程可以是可结合的,或者是可分离的;
可结合的线程能够被其他线程收回其资源和杀死。在被其他线程回收之前,它的存储器资源(例如栈)是没有被释放的,相反一个分离的线程是不能被其他线程回收或 杀死的。它的存储器资源在它终止时由系统自动释放;
为避免存储器泄漏,每个可结合线程都应该被其他线程显式地收回,要么通过调用pthread_detach函数被分离;
默认情况下,线程被创建成可结合的。
5.线程间的通讯方式(线程间的通信目的主要是用于线程同步,所以线程没有像进程通信中的用于数据交换的通信机制。)
锁机制:包括互斥锁、条件变量、读写锁
(1)临界区:当多个线程访问一个独占性共享资源时,可以使用临界区对象。拥有临界区的线程可以访问被保护起来的资源或代码段,其他线程若想访问,则被挂起,直到拥有临界区的线程放弃临界区为止。
(2)互斥量(Mutex):提供了以排他方式防止数据结构被并发修改的方法,互斥对象和临界区对象非常相似,只是其允许在进程间使用,也可在线程间使用,而临界区只限制与同一进程的各个线程之间使用。
(3)条件变量:以原子的方式阻塞进程,直到某个特定条件为真为止,一个线程被挂起,直到某件事件发生。
条件变量始终与互斥锁一起使用。
(4)信号量(semaphore):当需要一个计数器来限制可以使用某共享资源的线程数目时,可以使用“信号量”对象。CSemaphore类对象保存了对当前访问某一个指定资源的线程的计数值,该计数值是当前还可以使用该资源的线程数目。如果这个计数达到了零,则所有对这个CSemaphore类对象所控制的资源的访问尝试都被放入到一个队列中等待,直到超时或计数值不为零为止。mutex是semaphore的一种特殊情况(n=1时)。也就是说,完全可以用后者替代前者。但是,因为mutex较为简单,且效率高,所以在必须保证资源独占的情况下,还是采用这种设计。
(5)信号:类似进程间的信号处理
(6)事件:允许一个线程在处理完一个任务后,主动唤醒另外一个线程执行任务。
(7)套接字:可用于两个机器之间
三、进程和线程的区别
1.实际意义的区别
(1)一个程序至少有一个进程,一个进程至少有一个线程。线程(Thread)是进程的一个实体,是CPU调度和分派的基本单位;
(2)进程拥有独立的内存单元,而多个线程共享内存。从而线程效率更高;
(3)进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮;
(4)进程切换时,耗费资源较大,效率要差一些;
(5)进程是系统资源分配的基本单位,线程是调度的基本单位。
2.比较进程线程的优点
(1)易于调度。
(2)提高并发性。通过线程可方便有效地实现并发性。进程可创建多个线程来执行同一程序的不同部分。
(3)开销少。创建线程比创建进程要快,所需开销很少。
(4)利于充分发挥多处理器的功能。
3.相比进程线程的缺点
(1)线程之间的同步和加锁控制比较麻烦
(2)一个线程的崩溃影响到整个程序的稳定性
(3)线程多了之后,线程本身的调度也是一个麻烦事儿,需要消耗较多的CPU
4.通讯的区别
(1)每个进程有自己的地址空间。两个进程中的地址即使值相同,实际指向的位置也不同。进程间通信一般通过操作系统的公共区进行。
同一进程中的线程因属同一地址空间,可直接通信。
(2)只有进程间需要通信,同一进程的线程share地址空间,没有通信的必要,但要做好同步/互斥mutex,保护共享的全局变量。线程拥有自己的栈。同步/互斥是原语primitives. 而进程间通信无论是信号,管道pipe还是共享内存都是由操作系统保证的,是系统调用.
(3)线程间通信:由于多线程共享地址空间和数据空间,所以多个线程间的通信是一个线程的数据可以直接提供给其他线程使用,而不必通过操作系统(也就是内核的调度)。进程间的通信则不同,它的数据空间的独立性决定了它的通信相对比较复杂,需要通过操作系统。以前进程间的通信只能是单机版的,现在操作系统都继承了基于套接字(socket)的进程间的通信机制。这样进程间的通信就不局限于单台计算机了,实现了网络通信。
5.切换和调度
线程上下文切换比进程上下文切换要快得多,在多线程程序下,进程不是一个可执行的实体
附:进程和线程的简单理解
计算机的核心是CPU,它承担了所有的计算任务。它就像一座工厂,时刻在运行。假定工厂的电力有限,一次只能供给一个车间使用。也就是说,一个车间开工的时候,其他车间都必须停工。背后的含义就是,单个CPU一次只能运行一个任务。进程就好比工厂的车间,它代表CPU所能处理的单个任务。任一时刻,CPU总是运行一个进程,其他进程处于非运行状态。一个车间里,可以有很多工人。他们协同完成一个任务。线程就好比车间里的工人。车间的空间是工人们共享的,比如许多房间是每个工人都可以进出的。这象征一个进程的内存空间是共享的,每个线程都可以使用这些共享内存。一个进程可以包括多个线程可是,每间房间的大小不同,有些房间最多只能容纳一个人,比如厕所。里面有人的时候,其他人就不能进去了。这代表一个线程使用某些共享内存时,其他线程必须等它结束,一个防止他人进入的简单方法,就是门口加一把锁。先到的人锁上门,后到的人看到上锁,就在门口排队,等锁打开再进去。这就叫"互斥锁"(Mutual exclusion,缩写 Mutex),防止多个线程同时读写某一块内存区域。才能使用这一块内存。。还有些房间,可以同时容纳n个人,比如厨房。也就是说,如果人数大于n,多出来的人只能在外面等着。这好比某些内存区域,只能供给固定数目的线程使用。这时的解决方法,就是在门口挂n把钥匙。进去的人就取一把钥匙,出来时再把钥匙挂回原处。后到的人发现钥匙架空了,就知道必须在门口排队等着了。这种做法叫做"信号量"(Semaphore),用来保证多个线程不会互相冲突。不难看出,mutex是semaphore的一种特殊情况(n=1时)。也就是说,完全可以用后者替代前者。但是,因为mutex较为简单,且效率高,所以在必须保证资源独占的情况下,还是采用这种设计。
操作系统的设计,因此可以归结为三点:
(1)以多进程形式,允许多个任务同时运行;
(2)以多线程形式,允许单个任务分成不同的部分运行;
(3)提供协调机制,一方面防止进程之间和线程之间产生冲突,另一方面允许进程之间和线程之间共享资源。