因为进程具备独立性和异步性等并发特征,计算机的资源有限,致使了进程之间的资源竞争和共享,也致使了对进程执行过程的制约。数据结构
临界资源:一次只能供一个进程访问的资源。
临界区:把不容许多个并发进程交叉执行的一段程序称为临界区(critical region)或临界部分(critical section)。并发
临界区是由属于不一样并发进程的程序段共享公用数据或公用数据变量而引发的,临界区不可能用增长硬件的方法来解决。所以,临界区也能够被称为访问公用数据的那段程序。异步
当一个进程使用该临界资源时,其余须要访问该资源的进程必须阻塞,直到占用者释放该资源。测试
把这种因为共享某一公有资源而引发的在临界区内不容许并发进程交叉执行的现象,称为由共享公有资源而形成的对并发进程执行速度的间接制约。这里的“间接”二字主要是指各并发进程的速度受公有资源的制约,而非进程之间的直接制约。操作系统
互斥:一组并发进程中的一个或多个程序段,因共享某一公有资源而致使它们必须以一个不容许交叉执行的单位执行。也就是说,不容许两个以上的共享该资源的并发进程同时进入临界区。设计
通常状况下,做为程序段的一个过程不容许多个进程同时访问它。但若是该过程是纯过程,则各并发进程能够同时访问它。纯过程是指在执行过程当中不改变过程自身代码的一类过程。指针
一组并发进程互斥执行时必须知足以下准则:code
对临界区加锁以实现互斥。当某个进程进入临界区后,它将锁上临界区,直到它退出临界区为止。并发进程在申请进入临界区时,首先测试该临界区是否上锁。队列
加锁实现中的lock(key[S])和unlock(key[S])均为原子操做。有一点须要注意的是:在系统实现时锁定位key[S]老是设置在公有资源所对应的数据结构中的。进程
加锁实现的缺点:
A: lock(key[S]) <S> unlock(key[S]) Goto A
进程PB:
B: lock(key[S]) <S> unlock(key[S]) Goto B
因为两个进程中均有Goto语句(Goto A和Goto B),这就有可能出现其中一个进程的执行,致使另外一个进程长期得不处处理机资源,而处于永久饥饿状态(starvation)。
分析能够知道,一个进程可否进入临界区取决于进程本身调用lock过程去测试相应的锁定位。也就是说,每一个进程可否进入临界区是依靠进程本身的测试判断。这样,没有得到执行机会的进程固然没法判断,从而出现不公平现象。
那么是否有办法解决这个问题呢?固然,很明显,办法是有的,咱们能够为临界区设置一个管理员,由这个管理员来管理相应临界区的公有资源,它表明可用资源的实体,这个管理员就是信号量。
信号量和P、V原语是荷兰科学家E. W. Dijkstra提出来的。
【信号量】 在操做系统中,信号量sem是一个整数。
显然,用于互斥的信号量sem的初值应该大于0,而创建一个信号量必须说明所建信号量表明的意义,赋初值,以及创建相应的数据结构,以便指向那些等待使用该临界区的进程。
【P、V原语】
信号量的数值仅能由P、V原语操做改变。采用P、V原语,能够把类名为S的临界区描述为:When S do P(sem) 临界区 V(sem) od。
P原语操做:
V原语操做:
这里给出一个使用加锁法的软件实现方法来实现P、V原语:
P(sem): begin 封锁中断; lock(lockbit) val[sem]=val[sem]-1 if val[sem]<0 保护当前进程CPU现场 当前进程状态置为“等待” 将当前进程插入信号sem等待队列 转进程调度 fi unlock(lockbit);开放中断 end
V(sem): begin 封锁中断; lock(lockbit) val[sem]=val[sem]+1 if val[sem]<=0 local k 从sem等待队列中选取一个等待进程,将其指针置入k中 将k插入就绪队列 进程状态置位“就绪” fi unlock(lockbit);开放中断 end
设信号量sem是用于互斥的信号量,且其初始值为1表示没有并发进程使用该临界区。显然,由前面论述可知,只要把临界区置于P(sem)和V(sem)之间,便可实现进程之间的互斥。
用信号量实现两个并发进程PA和PB互斥的描述以下:
(1)设sem为互斥信号量,其取值范围为(1,0,-1)。其中sem=1表示进程PA和PB都未进入类名为S的临界区,sem=0表示进程PA或PB已进入类名为S的临界区,sem=-1表示进程PA和PB中,一个进程已进入临界区,而另外一个进程等待进入该临界区。
(2)实现过程:
Pa: P(sem) <S> V(sem) . . .
Pb: P(sem) <S> V(sem) . . .
【进程间的直接制约】:一组在异步环境下的并发进程,各自的执行结果互为对方的执行条件,从而限制各进程的执行速度的过程称为并发进程间的直接制约。这里的异步环境主要是指各并发进程的执行起始时间的随机性和执行速度的独立性。
【进程间的同步】:把异步环境下的一组并发进程因直接制约而互相发送消息而进行互相合做、互相等待,使得各进程按必定的速度执行的过程称为进程间的同步。
具备同步关系的一组并发进程称为合做进程,合做进程间相互发送的信号称为消息或事件。
用消息实现进程同步:
用 wait(消息名) 表示进程等待合做进程发来的消息。 用 signal(消息名) 表示向合做进程发送消息。 过程wait的功能是等待到消息名为true的进程继续执行,而signal的功能则是向合做进程发送合做进程所须要的消息名,并将其值置为true。
【进程互斥和进程同步】:进程同步不一样于进程互斥,进程互斥时它们的执行顺序能够是任意的。通常来讲,也能够把个进程之间发送的消息做为信号量看待。与进程互斥时不一样的是,这里的信号量只与制约进程及被制约进程有关,而不是与整租并发进程有关。所以,称该信号量为私用信号量(private semaphore)。一个进程Pi的私用信号量semi是从制约进程发送来的进程Pi的执行条件所须要的信息。与私用信号量相对应,称互斥时使用的信号量为公用信号量。
【用P、V原语实现进程同步】:
首先为各并发进程设置私用信号量,而后为私用信号量赋初值,最后利用P、V原语和私用信号量规定各进程的执行顺序。
把并发进程的同步和互斥问题通常化,能够获得一个抽象的通常模型,即生产者-消费者问题(producer-consumer problems)。
把系统中使用某一类资源的进程称为该资源的消费者,而把释放同类资源的进程称为该资源的生产者。
设生产者进程和消费者进程是互相等效的,其中,各生产者进程使用的过程deposit(data)和各消费者使用的进程remove(data)可描述以下:
首先,能够看到,上述生产者-消费者问题是一个同步问题。即生产者和消费者之间知足以下条件:
另外,因为有界缓冲区是临界资源,所以,各生产者进程和各消费者进程之间必须互斥执行。
设公用信号量mutex保证生产者进程和消费者进程之间的互斥,设信号量avail为生产者进程的私用信号量,信号量full为消费者进程的私用信号量。信号量avail表示有界缓冲区中的空单元数,初值为n;信号量full表示有界缓冲区中非空单元数,初始值为0。信号量mutex表示可用有界缓冲区的个数,初始值为1。
deposit(data): begin P(avail) // 检查是否有空单元可使用 P(mutex) // 检查临界区是否被占用 送数据入缓冲区某单元 V(full) V(mutex) end
remove(data): begin P(full) // 检查是否有非空单元 P(mutex) // 检查临界区 取缓冲区中某单元数据 V(avail) V(mutex) end
在这个例子中,因为包含多个公用信号量和私用信号量,所以P、V原语的操做顺序须要很是当心。通常来讲,因为V原语是释放资源,因此能够以任意次序出现。但P原语则否则,若是次序混乱,将会形成进程之间的死锁。例如:若是咱们调换P(full)和P(mutex),便有可能致使程序一直占用临界区,而没法获得资源(若是此时full=0,mutex >= 0,程序进入临界区后得不到资源,但又没法释放临界区),从而致使死锁。
【其余】 设计:先看是否存在互斥,给出公用信号量;再看同步,给出私用信号量。互斥和同步分开操做。 操做:先对同步的私用信号量作P操做,而后对互斥的公用信号量作P操做。