进程和程序的本质区别在于动态和静态特征
系统中感知进程的唯一实体是PCB(进程控制块,process control block)
进程和线程的区别:
进程是执行中的程序,一个进程中包含若干线程,它们共享进程所拥有的资源。在OS中,进程是分配资源的基本单位,线程是独立运行和独立调度的基本单位,线程比进程要小,基本上不拥有系统资源,因此调度的开销也更小。线程和进程的区别在于,子进程和父进程之间有不同的代码和数据空间,而线程则共享其所属进程的数据空间。
总结:(1)就地址空间和其它资源而言,进程之间相互独立,而同一进程的各线程间共享,某一进程的线程在其他进程中不可见。(2)就通讯而言,进程间通信IPCI(Inter-Process Communication)通过操作系统,线程间可以直接读写进程数据段(如全局变量)来进行通信——需要进程同步和互斥手段的辅助,以保证数据一致性。(3)就调度和切换,线程上下文切换比进程上下文切换快得多。
进程状态转换:①运行②就绪③阻塞
运行:当一个进程在处理器上运行时,称其为运行状态,对于单处理器系统来说,处于运行状态的进程只有一个。在没有其他进程可执行时(比如所有进程都处于阻塞状态),通常会自动执行系统的空闲进程。
就绪:当一个进程获得了除处理器以外的一切所需资源,一旦得到处理器就可运行,称之为就绪。就绪进程可以按照优先级来划分队列,比如,当一个进程由于时间片用完而进入就绪状态时,排入低优先级队列,当进程由I/O 操作完成而进入就绪状态时,处于高优先级队列
阻塞:也称等待或睡眠,即一个进程正在等待某一事件的发生(例如请求I/O而等待I/O 完成)而暂时停止运行,这样即使把处理器分配给进程也无法运行,故称之为阻塞。
一次只能被一个进程所占用的资源就是所谓的临界资源。典型的临界资源比如物理上的打印机,或是存在硬盘或内存中被多个进程所共享的一些变量和数据等(如果这类资源不被看成临界资源加以保护,那么很有可能造成丢数据的问题)。
(1) 进程同步-进程之间的合作(比如进程B需要从缓冲区读取进程A的信息,当缓冲区为空时,因为进程B读不到信息而阻塞,当进程A产生信息放入缓冲区时,进程B才被唤醒)
(2) 进程互斥-进程之间的制约(当一个进程A进入临界区使用临界资源,另一个进程B必须等待,只有当前临界资源被A释放后,B才能解除阻塞状态)
实现临界区互斥的基本方法
硬件实现方法
通过硬件实现临界区最简单的办法就是(关CPU的中断)。从计算机原理我们知道,CPU进行进程切换是需要通过中断来进行。如果屏蔽了中断那么就可以保证当前进程顺利的将临界区代码执行完,从而实现了互斥。这个办法的步骤就是:(屏蔽中断--执行临界区--开中断)。但这样做并不好,这大大限制了处理器交替执行任务的能力。并且将关中断的权限交给用户代码,那么如果用户代码屏蔽了中断后不再开,那系统岂不是跪了?
还有硬件的指令实现方式,这个方式和接下来要说的信号量方式如出一辙。但是通过硬件来实现,这里就不细说了。
信号量实现方式
这也是我们比较熟悉P V操作。通过设置一个表示资源个数的信号量S,通过对信号量S的P和V操作来实现进程的的互斥。
P和V操作分别来自荷兰语Passeren和Vrijgeven,分别表示占有和释放。P V操作是操作系统的原语,意味着具有原子性。
P操作首先减少信号量,表示有一个进程将占用或等待资源,然后检测S是否小于0,如果小于0则阻塞,如果大于0则占有资源进行执行。
V操作是和P操作相反的操作,首先增加信号量,表示占用或等待资源的进程减少了1个。然后检测S是否小于0,如果小于0则唤醒——等待使用S资源的其它进程。
一些经典利用信号量实现同步的问题
生产者--消费者问题
问题描述:生产者-消费者问题是一个经典的进程同步问题,该问题最早由Dijkstra提出,用以演示他提出的信号量机制。本作业要求设计在同一个进程地址空间内执行的两个线程。生产者线程生产物品,然后将物品放置在一个空缓冲区中供消费者线程消费。消费者线程从缓冲区中获得物品,然后释放缓冲区。当生产者线程生产物品时,如果没有空缓冲区可用,那么生产者线程必须等待消费者线程释放出一个空缓冲区。当消费者线程消费物品时,如果没有满的缓冲区,那么消费者线程将被阻塞,直到新的物品被生产出来
这里生产者和消费者是既同步又互斥的关系,首先只有生产者生产了,消费着才能消费,这里是同步的关系。但他们对于临界区的访问又是互斥的关系。因此需要三个信号量empty和full用于同步缓冲区,而mut变量用于在访问缓冲区时是互斥的。
读者--写者问题
问题描述:
一个数据文件或记录,统称数据对象,可被多个进程共享,其中有些进程只要求读称为"读者",而另一些进程要求写或修改称为"写者"。
规定:允许多个读者同时读一个共享对象,但禁止读者、写者同时访问一个共享对象,也禁止多个写者访问一个共享对象,否则将违反Bernstein并发执行条件。
通过描述可以分析,这里的读者和写者是互斥的,而写者和写者也是互斥的,但读者之间并不互斥。
由此我们可以设置3个变量,一个用来统计读者的数量,另外两个分别用于对读者数量读写的互斥,读者和写着,写者和写者的互斥。
哲学家进餐问题
问题描述:
有五个哲学家,他们的生活方式是交替地进行思考和进餐。哲学家们公用一张圆桌,周围放有五把椅子,每人坐一把。在圆桌上有五个碗和五根筷子,当一个哲学家思考时,他不与其他人交谈,饥饿时便试图取用其左、右最靠近他的筷子,但他可能一根都拿不到。只有在他拿到两根筷子时,方能进餐,进餐完后,放下筷子又继续思考。
根据问题描述,五个哲学家分别可以看作是五个进程。五只筷子分别看作是五个资源。只有当哲学家分别拥有左右的资源时,才得以进餐。如果不指定规则,当每个哲学家手中只拿了一只筷子时会造成死锁,从而五个哲学家都因为吃不到饭而饿死。因此我们的策略是让哲学家同时拿起两只筷子。因此我们需要对每个资源设置一个信号量,此外,还需要使得哲学家同时拿起两只筷子而设置一个互斥信号量。
死锁:在多个程序同时执行的情况下,多个进程之间可能出现竞争一定数量的资源,若某个进程申请资源,则此时资源不可用,那么即将进入等待状态,如果所申请的资源被其他等待进程所占有,那么该进程有可能永远处于等待状态而无法改变状态。——这就是死锁情况。
产生死锁的原因是:
(1) 因为系统资源不足
(2) 进程运行推进的顺序不合适
(3) 资源分配不对等
产生死锁的四个必要条件是:
(1) 互斥条件,一个资源每次只能被一个进程使用,如果有另一个进程申请该资源,那么申请进程必须等到该资源被释放为止。
(2) 请求与保持条件(占有并等待),一个进程必须占有至少一个资源,并等待另一为其他进程所占有的资源
(3) 不剥夺条件(非抢占)),进程已获得的资源,在未使用完之前,不能强行剥夺,只能在进程完成任务和自动释放
(4) 循环等待条件,若干进程之间形成的一种头尾相接的循环等待资源关系,例如有一组等待进程{p0,p1,p2,p3,p4}, p0 等待的资源为p1所占有,p1 等待的资源为p2所占有,p2等待的资源为p3所占有,p3 等待的资源为p4所占有,而p4 等待的资源为P1 所占有。
无论static还是非static的全局变量,不加限制随意访问都可能出现同步问题;
无论static还是非static的局部变量,每个线程都是私有的,其他的线程不会对其进行干扰,因此不会出现同步问题。
有5个可用的某类资源,由四个进程共享,每个进程最多可申请(?)个资源,使系统不死锁?
设临界资源为m, 共享进程为n个,每个进程最多可以申请x个资源,则
当m>n 时,m>n(x-1) 使系统不死锁,当m<n 时,x=1;
因此x=2;
解决死锁的基本方法:
预防死锁:
资源一次性分配:(破坏请求和保持条件)
可剥夺资源:即当某进程新的资源未满足时,释放已占有的资源(破坏不可剥夺条件)
资源有序分配法:系统给每类资源赋予一个编号,每一个进程按编号递增的顺序请求资源,释放则相反(破坏环路等待条件)
避免死锁:
预防死锁的几种策略,会严重地损害系统性能。因此在避免死锁时,要施加较弱的限制,从而获得 较满意的系统性能。由于在避免死锁的策略中,允许进程动态地申请资源。因而,系统在进行资源分配之前预先计算资源分配的安全性。若此次分配不会导致系统进入不安全状态,则将资源分配给进程;否则,进程等待。其中最具有代表性的避免死锁算法是银行家算法。
检测死锁
首先为每个进程和每个资源指定一个唯一的号码;
然后建立资源分配表和进程等待表,例如:
解除死锁:
当发现有进程死锁后,便应立即把它从死锁状态中解脱出来,常采用的方法有:
剥夺资源:从其它进程剥夺足够数量的资源给死锁进程,以解除死锁状态;
撤消进程:可以直接撤消死锁进程或撤消代价最小的进程,直至有足够的资源可用,死锁状态.消除为止;所谓代价是指优先级、运行代价、进程的重要性和价值等。