操作系统第六章-同步

文章目录


前言
两个进程之间可以使独立的也可以是协作的,协作进程能与系统内的其他执行进程相互影响.协作进程或能直接共享逻辑地址空间,或能通过文件或消息来共享数据.而 共享数据的并发访问可能导致数据的不一致

1.临界区问题

1.临界资源
临界资源是一次仅允许一个进程使用的共享资源。各进程采取互斥的方式,实现共享的资源称作临界资源。属于临界资源的硬件有,打印机,磁带机等;软件有消息队列,变量,数组,缓冲区等。诸进程间采取互斥方式,实现对这种资源的共享。

2.临界区:
每个进程中访问临界资源的那段代码称为临界区(criticalsection),每次只允许一个进程进入临界区,进入后,不允许其他进程进入。不论是硬件临界资源还是软件临界资源,多个进程必须互斥的对它进行访问。多个进程涉及到同一个临界资源的的临界区称为相关临界区。使用临界区时,一般不允许其运行时间过长,只要运行在临界区的线程还没有离开,其他所有进入此临界区的线程都会被挂起而进入等待状态,并在一定程度上影响程序的运行性能。(查看原文)

临界区问题是设计一个协议以便协作进程

  • 协作进程结构
    操作系统第六章-同步
    在进入临界区前,每个进程应请求许可.实现请求的代码区称为进入区.临界区之后有退出区,其他代码为剩余区
  • 临界区问题的解决方案应满足互斥,进步,有限等待
    • 互斥:进程Pi在临界区内执行,其他进程不能在其临界区内执行
    • 进步:如果没有进程在其临界区内执行,并且有进程需要进入临界区,那么只有那些不在剩余区内执行的进程可以参加选择,以便确定谁能下次进入临界区,而且这种选择不能无线推迟
    • 有限等待:从一个进程做出进入临界区的请求直到这个请求允许为止,其他进程允许进入其临界区的次数具有上限
  • 处理临界区的两种方法:抢占式内核和非抢占式内核
    • 抢占式内核允许处于内核模式的进程被抢占
    • 非抢占式内核不允许处于内核模式的进程被抢占,处于内核模式运行的进程会一直运行,直到退出内核模式,阻塞或自愿放弃CPU控制

2.硬件同步

基于加锁(locking)为前提,即通过锁来保护临界区.通过硬件指令来解决临界区问题

3.互斥锁

一个进程在进入临界区时应得到锁,在退出临界区时释放锁
操作系统第六章-同步
伪代码

/*available为true,表示锁可用,进程能够进入临界区*/
acquire(){
	while(!available){};//忙等待busy wait
	available = false;
}

release(){
	available = true;
}

忙等待:当一个进程在临界区中,任何其他进程在进入临界区时必须不断循环判断锁是否可用.这种互斥锁称为自旋锁,进程不停的旋转,以等待所变得可用
忙等待浪费CPU资源(CPU需要分配资源来不停的执行循环),优点是没有上下文切换(因为协作进程的代码是都在执行的)

4.信号量(semaphore)

一个信号量S是一个整型变量.除了初始化外,只能通过两个标准原子操作:wait()和signal()来访问
wait()称为P原语,用作测试signal()称为V原语,用作增加

伪代码

/*wait()*/
wait(S){
	while(S <= 0){};//忙等待busy wait
	S--;
}

/*signal()*/
signal(S){
	S++;
}
  • 操作系统通常区分计数信号量(其值可以使任意整数)与二进制信号量(S只能是0或者1,类似于互斥锁)

  • 进程信号量可以用于控制访问具有多个实例的临界资源.信号量的初值为可用资源数量:

      例子:
      假设有3个协作进程(取名A B C)都需要使用打印机,打印机有2个.
      信号量的初值S=2.
      A进入临界区时执行wait(),不满足循环条件,S--,S=1;获得打印机执行,可用打印机为1个
      B进入临界区时执行wait(),不满足循环条件,S--,S=0;获得打印机执行,可用打印机为0个
      C进入临界区时执行wait(),满足循环条件,一直在循环中,进行忙等待
      若此时A使用完了打印机,会执行signal(),S++,S=1,可用打印机为1个,C跳出循环,执行S--操作;获得打印机执行,可用打印机为0个
    

    当信号量的计数为0时,所有资源都在使用中,后面使用资源的进程将会阻塞,知道计数大于0

5.死锁与饥饿

操作系统第六章-同步
假设有一个系统,有有两个进程p0和p1,两个进程都有共享信号量S和Q,初值均为1:
若p0和p1同时执行,p0执行wait(S),S=0;p1执行wait(Q),Q=0,现在问题就出来了,p0执行wait(Q),和p1执行wait(S),两个进程就会一直等在这里,这两个进程都在等待signal()事件发生,这个状态就称为死锁,导致了无限阻塞或饥饿

6.经典同步问题

1. 有界缓冲问题(生产者-消费者问题)

通过一组信号量,来控制协作进程之间的同步协调工作

伪代码

/*一组信号量*/
int n;//n表示有n个缓冲区//本例n=5
semaphore mutex = 1;//提供缓冲池访问的互斥要求
semaphore empty= n;//表示空的缓冲区的数量
semaphore full = 0;//表示已使用缓冲区的数量

/*生产者进程*/
do{
	....
	/*produce an item in nextproduced*/
	....
	wait(empty);//缓冲区是否有空余
	wait(mutex);
	....
	/*add next produced to the buffer*/
	....
	signal(mutex);
	signal(full);
}while(true)

/*消费者进程*/
do{
	wait(full);//判断缓冲区是否有产品
	wait(mutext);
	....
	/*remove an item from buffer to next consumed*/
	....
	signal(mutex);
	signal(empty);
	....
	/*consume the item in next consumed*/
	....
}while(true)

2.哲学家问题

操作系统第六章-同步
如图,有五个进程P0-P4,每个进程之间有临界资源(如p0和p1之间有临界资源R0),进程Pi只有同时拥有Ri和R_(i+1)%5才能进入临界区

伪代码

do{
	wait(R[i]);
	wait(R[(i+1)%5]);
	....
	/*run for a while*/
	....
	signal(R[i]);
	signal(R[(i+1)%5]);
	....
}while(true)

若此时进程pi同时使用其Ri,这样就造成了五个进程都停在wait(R[i]),进而五个进程都执行不了,形成了死锁

死锁问题的不就措施:

  1. 最多允许4个进程同时执行
  2. 只用一个进程的两个临界资源都可用时,才能拥有执行权
  3. 使用非对称解决方案:单号的进程Pi先拿起Ri再拿起R_(i+1)%5,双号的进程Pi先拿起R_(i+1)%5再拿起Ri
上一篇:面试题 | 一个公家单位的面试


下一篇:897. 最长公共子序列