第2篇 进程同步

声明:本博客为学习操作系统时所做笔记,主要资料来源为《操作系统概念》(第七版)以及“C语言中文网”中的操作系统篇,如有不妥之处,再修改或者删除。“C语言中文网址”如下:

http://c.biancheng.net/cpp/u/xitong/

1 进程同步

1.1 临界资源

临界资源概念:一次仅允许一个进程使用的资源称为临界资源。对临界资源的访问,必须互斥地进行,在每个进程中,访问临界资源的那段代码称为临界区。

临界资源的访问过程分成四个部分:

①进入区:为了进入临界区使用临界资源,在进入区要检查可否进入临界区,如果可以进入临界区,则应设置正在访问临界区的标志,以阻止其他进程同时进入临界区。

②临界区:进程中访问临界资源的那段代码,又称临界段。

③退出区:将正在访问临界区的标志清除。

④剩余区:代码中的其余部分。

临界区文体的解答必须满足三项要求:互斥、前进、有限等待。

同步:同步亦称直接制约关系,它是指为完成某种任务而建立的两个或多个进程,这些进程因为需要在某些位置上协调它们的工作次序而等待、传递信息所产生的制约关系。

互斥:互斥亦称间接制约关系。当一个进程进入临界区使用临界资源时,另一个进程必须等待, 当占用临界资源的进程退出临界区后,另一进程才允许去访问此临界资源。

1.2 临界区问题的解答

软件实现方法:

1) 算法一:单标志法。

优点:该算法可确保每次只允许一个进程进入临界区。

缺点:两个进程必须交替进入临界区,如果某个进程不再进入临界区了,那么另一个进程也将无法进入临界区(违背“空闲让进”)这样很容易造成资源利用的不充分。

// P0进程
while(turn!=0);
critical section;
turn=1;
remainder section;

// P1进程
while(turn!=1);  // 进入区
critical section;  // 临界区
turn = 0;  // 退出区
remainder section;  // 剩余区

2)算法二:双标志法先检查。

优点:不用交替进入,可连续使用;

缺点:Pi和Pj可能同时进入临界区。按序列①②③④ 执行时,会同时进入临界区(违背“忙则等待”)。

// Pi 进程
while(flag[j]);  // ①
flag[i]=TRUE;  // ③  
critical section;   
flag[i] = FALSE; 
remainder section;

// Pj 进程
while(flag[i]);  // ② 进入区
flag[j] =TRUE;  // ④ 进入区
critical section;  // 临界区
flag[j] = FALSE;  // 退出区
remainder section;  // 剩余区

3) 算法三:双标志法后检查。

缺点:当两个进程几乎同时都想进入临界区时,它们分别将自己的标志值flag设置为TRUE,并且同时检测对方的状态(执行while语句),发现对方也要进入临界区,于是双方互相谦让,结果谁也进不了临界区,从而导致“饥饿”现象。

// Pi进程
flag[i] =TRUE;
while(flag[j]);
critical section;
flag[i] =FLASE;
remainder section;

// Pj进程
flag[j] =TRUE;  // 进入区
while(flag[i]);  // 进入区
critical section;  // 临界区
flag [j] =FLASE;   // 退出区
remainder section;  // 剩余区

4)算法四:Peterson’s Algorithm。

基本思想是算法一和算法三的结合。利用flag解决临界资源的互斥访问,而利用turn解决“饥饿”现象。

// Pi进程
flag[i]=TURE; turn=j;
while(flag[j]&&turn==j); 
critical section;
flag[i]=FLASE;
remainder section;

// Pj进程
flag[j] =TRUE;turn=i;  // 进入区
while(flag[i]&&turn==i);   // 进入区
critical section;  // 临界区
flag[j]=FLASE;  // 退出区
remainder section;  // 剩余区

硬件实现方法

许多现代操作系统提供了特殊硬件指令以允许原子地(不可中断地)检查和修改字的内容或交换两个字的内容。

TestAndSet指令:这条指令是原子操作,即执行该代码时不允许被中断。其功能是读出指定标志后把该标志设置为真。

Swap指令:该指令的功能是交换两个字节的内容。

硬件方法的优点:适用于任意数目的进程,不管是单处理机还是多处理机;简单、容易验证其正确性。可以支持进程内有多个临界区,只需为每个临界区设立一个布尔变量。

硬件方法的缺点:进程等待进入临界区时要耗费处理机时间,不能实现让权等待。从等待进程中随机选择一个进入临界区,有的进程可能一直选不上,从而导致“饥饿”现象。

1.3 信号量(semaphore)

信号量(S)是个整数变量,除此初始化之外,它只能通过两个标准原子操作:wait()和signal()来访问。

通常操作系统将信号量分为二进制信号量计数信号量

wait() {                    
    while(S <= 0);
    S--;
}

signal() {
    S++;
}

1)用法:解决互斥问题。

二进制信号量可以被用来解决多进程的临界区问题,n个进程共享一个信号量mutex,并初始化为1。每个进程的结构如下:

do {
    wait(mutex);
        //critical section
    signal(mutex);
        //remainder section
}while(TRUE);

计数信号量可以用来控制访问若干实例的某种资源,该信号量初始化为可用资源的数量。

2)用法:解决同步问题。

例如:有两个并发进程:P1有语句S1而P2有语句S2,假设要求S1执行完后在执行S2。则使P1和P2共享一个共同信号量synch,并初始化为0。

//进程P1插入语句
S1;
signal(synch);
//进程P2插入语句
wait(synch);
S2;

信号量的关键之处是它们能原子的执行。必须确保没有两个进程能对对一信号量执行操作wait()和signal()。在单处理器环境下,可以在执行wait()和signal()操作时简单地禁止中断。多处理器环境下,必须禁止每个处理器的中断,但是这比较困难,所以,SMP系统必须提供其他加锁技术(如自旋锁),确保wait()和signal()原子执行

3)分析进程同步和互斥问题的方法步骤

①关系分析。找出问题中的进程数,并且分析它们之间的同步和互斥关系。同步、互斥、前驱关系直接按照上面例子中的经典范式改写。

②整理思路。找出解决问题的关键点,并且根据做过的题目找出解决的思路。根据进程的操作流程确定P操作、V操作的大致顺序。

③设置信号量。根据上面两步,设置需要的信号量,确定初值,完善整理。

1.4 死锁和饥饿

死锁(deallocked):两个或多个进程无限等待一个事件,该事件只能由这些等待的进程之一来产生。

例如:两个进程P0和P1组成的系统,每个都访问共享信号量S和Q,这两个信号量初值都为1:

    P0                  P1
wait(S);            wait(Q);
wait(Q);            wait(S);
    .                   .
    .                   .
    .                   .
signal(S);          signal(Q);
signal(Q);          signal(S);

若出现如下执行顺序,则发生死锁:P0:wait(S)->P1:wait(Q)->P0:wait(Q)->P1->wait(S)。

1.5 经典同步问题

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

http://c.biancheng.net/cpp/html/2600.html

2)读者-写者问题

http://c.biancheng.net/cpp/html/2601.html

3)哲学家进餐问题

http://c.biancheng.net/cpp/html/2602.html

4)吸烟者问题

http://c.biancheng.net/cpp/html/2603.html

1.6 管程

管程:是由一组数据以及定义在这组数据之上的对这组数据的操作组成的软件模块,这组操作能初始化并改变管程中的数据和同步进程。

管程类型提供了一组由程序员定义的、在管程内互斥的操作。由于管程是一个语言成分,所以管程的互斥访问完全由编译程序在编译时自动添加,无需程序员关注,而且保证正确。

发布了54 篇原创文章 · 获赞 14 · 访问量 4万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章