经典进程的同步问题

本文摘自汤小丹主编《计算机操作系统》(第三版)2.4 经典进程的同步问

在多道程序环境下,进程同步问题十分重要,也是相当有趣的问题,因而吸引了不少 学者对它进行研究,由此而产生了一系列经典的进程同步问题,其中较有代表性的是“生 产者—消费者”问题、“读者—写者问题”、“哲学家进餐问题”等等。通过对这些问题的研 究和学习,可以帮助我们更好地理解进程同步的概念及实现方法。


生产者—消费者问题

前面我们已经对生产者—消费者问题(The proceducer-consumer problem)做了一些描述, 但未考虑进程的互斥与同步问题,因而造成了数据(Counter)的不定性。由于生产者—消费者 问题是相互合作的进程关系的一种抽象,例如,在输入时,输入进程是生产者,计算进程 是消费者;而在输出时,计算进程是生产者,而打印进程是消费者。因此,该问题有很大 的代表性及实用价值。本小节将利用信号量机制来解决生产者—消费者问题。

1. 利用记录型信号量解决生产者—消费者问题

假定在生产者和消费者之间的公用缓冲池中,具有 n 个缓冲区,这时可利用互斥信号 量 mutex 实现诸进程对缓冲池的互斥使用。利用信号量 empty 和 full 分别表示缓冲池中空缓 冲区和满缓冲区的数量。又假定这些生产者和消费者相互等效,只要缓冲池未满,生产者 便可将消息送入缓冲池;只要缓冲池未空,消费者便可从缓冲池中取走一个消息。对生产 者—消费者问题可描述如下:

Var mutex,empty,full: semaphore:=1,n,0;     
buffer:array[0,...,n-1] of item; 
    in,out: integer:=0,0;
    begin
        parbegin 
            proceducer: begin
                            repeat
                                ...
                            producer an item nextp;
                                ... 
                            wait(empty); 
                            wait(mutex); 
                            buffer(in):=nextp;
                            in:=(in+1) mod n; 
                            signal(mutex); 
                            signal(full);
                            until false;
                        end 
            consumer: begin
                        repeat
                            wait(full);
                            wait(mutex); 
                            nextc:=buffer(out); 
                            out:=(out+1) mod n; 
                            signal(mutex); 
                            signal(empty);
                            consumer the item in nextc;
                         until false; 
                       end
        parend 
    end

在生产者—消费者问题中应注意:首先,在每个程序中用于实现互斥的 wait(mutex)和 signal(mutex)必须成对地出现;其次,对资源信号量 empty 和 full 的 wait 和 signal 操作,同 样需要成对地出现,但它们分别处于不同的程序中。例如,wait(empty)在计算进程中,而 signal(empty)则在打印进程中,计算进程若因执行 wait(empty)而阻塞,则以后将由打印进程 将它唤醒;最后,在每个程序中的多个 wait 操作顺序不能颠倒,应先执行对资源信号量的 wait 操作,然后再执行对互斥信号量的 wait 操作,否则可能引起进程死锁。

2. 利用 AND 信号量解决生产者—消费者问题

对于生产者—消费者问题,也可利用 AND 信号量来解决,即用 Swait(empty,mutex) 来代替wait(empty)和wait(mutex);用Ssignal(mutex,full)来代替signal(mutex)和signal(full); 用 Swait(full,mutex)来代替 wait(full)和 wait(mutex),以及用 Ssignal(mutex,empty)代替 Signal(mutex)和 Signal(empty)。利用 AND 信号量来解决生产者—消费者问题的算法描述 如下:

Var mutex,empty,full: semaphore:=1,n,0;
    buffer:array[0,...,n-1] of item;
    in out: integer:=0,0;
    begin
        parbegin
            producer: begin 
                        repeat
                            ...
                            produce an item in nextp;
                            ...
                            Swait(empty,mutex);

                        
                            buffer(in):=nextp; 
                            in:=(in+1)mod n;
                            Ssignal(mutex,full);
                         until false; 
                       end
            consumer:begin 
                        repeat
                            Swait(full,mutex); 
                            Nextc:=buffer(out); 
                            Out:=(out+1) mod n; 
                            Ssignal(mutex,empty); 
                            consumer the item in nextc;
                        until false; 
                      end
        parend 
    end

3. 利用管程解决生产者—消费者问题

在利用管程方法来解决生产者—消费者问题时,首先便是为它们建立一个管程,并命 名为 ProclucerConsumer,或简称为 PC。其中包括两个过程:

  1. put(item)过程。生产者利用该过程将自己生产的产品投放到缓冲池中,并用整型变 量 count 来表示在缓冲池中已有的产品数目,当 count≥n 时,表示缓冲池已满,生产者须 等待。
  2. get(item)过程。消费者利用该过程从缓冲池中取出一个产品,当count≤0时,表示 缓冲池中已无可取用的产品,消费者应等待。

PC 管程可描述如下:

type producer-consumer=monitor
    Var in,out,count: integer;
        buffer: array[0, ..., n-1] of item;         notfull,notempty:condition; 
        procedure entry put(item)
            begin
                if count>=n then notfull.wait;
                    buffer(in):=nextp; 
                    in:=(in+1) mod n;
                    count:=count+1;
                    if notempty.queue then notempty.signal; 
                    end
        procedure entry get(item) 
            begin
                if count<=0 then notempty.wait;                 nextc:=buffer(out); 
                out:=(out+1) mod n; 
                count:=count-1;
                if notfull.quene then notfull.signal; 
            end
        begin in:=out:=0; 
    count:=0
    end

在利用管程解决生产者—消费者问题时,其中的生产者和消费者可描述为:

producer: begin 
             repeat
                 produce an item in nextp;
                 PC.put(item); 
                 until false;
          end 
consumer: begin
             repeat
                 PC.get(item);
                 consume the item in nextc;
             until false; 
          end


哲学家进餐问题

由 Dijkstra 提出并解决的哲学家进餐问题(The Dinning Philosophers Problem)是典型的同 步问题。该问题是描述有五个哲学家共用一张圆桌,分别坐在周围的五张椅子上,在圆桌 上有五个碗和五只筷子,他们的生活方式是交替地进行思考和进餐。平时,一个哲学家进 行思考,饥饿时便试图取用其左右最靠近他的筷子,只有在他拿到两只筷子时才能进餐。 进餐完毕,放下筷子继续思考。

1. 利用记录型信号量解决哲学家进餐问题

经分析可知,放在桌子上的筷子是临界资源,在一段时间内只允许一位哲学家使用。 为了实现对筷子的互斥使用,可以用一个信号量表示一只筷子,由这五个信号量构成信号 量数组。其描述如下:

Var chopstick: array[0,...,4] of semaphore;
 

所有信号量均被初始化为 1,第 i 位哲学家的活动可描述为:

repeat
    wait(chopstick[i]); 
    wait(chopstick[(i+1)mod 5]);
        ... 
    eat;
        ...
    signal(chopstick[i]); 
    signal(chopstick[(i+1)mod 5]);
        ... 
    think;
until false;

在以上描述中,当哲学家饥饿时,总是先去拿他左边的筷子,即执行 wait(chopstick[i]);
成功后,再去拿他右边的筷子,即执行 wait(chopstick[(i+1)mod 5]);又成功后便可进餐。进 餐完毕,又先放下他左边的筷子,然后再放右边的筷子。虽然,上述解法可保证不会有两 个相邻的哲学家同时进餐,但有可能引起死锁。假如五位哲学家同时饥饿而各自拿起左边 的筷子时,就会使五个信号量 chopstick 均为 0; 当他们再试图去拿右边的筷子时,都将因 无筷子可拿而无限期地等待。对于这样的死锁问题,可采取以下几种解决方法:

  1. 至多只允许有四位哲学家同时去拿左边的筷子,最终能保证至少有一位哲学家能够 进餐,并在用毕时能释放出他用过的两只筷子,从而使更多的哲学家能够进餐。
  2. 仅当哲学家的左、右两只筷子均可用时,才允许他拿起筷子进餐。
  3. 规定奇数号哲学家先拿他左边的筷子,然后再去拿右边的筷子,而偶数号哲学家则 相反。按此规定,将是 1、2 号哲学家竞争 1 号筷子;3、4 号哲学家竞争 3 号筷子。即五位 哲学家都先竞争奇数号筷子,获得后,再去竞争偶数号筷子,最后总会有一位哲学家能获 得两只筷子而进餐。

2. 利用 AND 信号量机制解决哲学家进餐问题

在哲学家进餐问题中,要求每个哲学家先获得两个临界资源(筷子)后方能进餐,这在本 质上就是前面所介绍的 AND 同步问题,故用 AND 信号量机制可获得最简洁的解法。描述 如下:

Var chopsiick array of semaphore:=(1,1,1,1,1);
    processi
        repeat 
            think;
            Sswait(chopstick[(i+1)mod 5],chopstick[i]); 
            eat;
            Ssignat(chopstick[(i+1)mod 5],chopstick[i]);
        until false;


读者—写者问题

一个数据文件或记录,可被多个进程共享,我们把只要求读该文件的进程称为“Reader 进程”,其他进程则称为“Writer 进程”。允许多个进程同时读一个共享对象,因为读操作不 会使数据文件混乱。但不允许一个 Writer 进程和其他 Reader 进程或 Writer 进程同时访问共 享对象,因为这种访问将会引起混乱。所谓“读者—写者问题(Reader-Writer Problem)”是 指保证一个 Writer 进程必须与其他进程互斥地访问共享对象的同步问题。读者—写者问题 常被用来测试新同步原语。

1. 利用记录型信号量解决读者—写者问题

为实现 Reader 与 Writer 进程间在读或写时的互斥而设置了一个互斥信号量 Wmutex。 另外,再设置一个整型变量 Readcount 表示正在读的进程数目。由于只要有一个 Reader 进 程在读,便不允许 Writer 进程去写。因此,仅当 Readcount=0,表示尚无 Reader 进程在读 时,Reader 进程才需要执行 Wait(Wmutex)操作。若 Wait(Wmutex)操作成功,Reader 进程便 可去读,相应地,做 Readcount+1 操作。同理,仅当 Reader 进程在执行了 Readcount 减 1 操作后其值为0时,才须执行signal(Wmutex)操作,以便让Writer进程写。又因为Readcount 是一个可被多个 Reader 进程访问的临界资源,因此,也应该为它设置一个互斥信号量 rmutex。

读者—写者问题可描述如下:

Var rmutex,wmutex: semaphore:=1,1;
    Readcount: integer:=0; 
    begin
        parbegin
            Reader: begin 
                        repeat
                            wait(rmutex);
                            if readcount=0 then wait(wmutex);
                                Readcount:=Readcount+1; 
                            signal(rmutex);
                                ...
                            perform read operation;
                                ... 
                            wait(rmutex);
                            readcount:=readcount-1;
                            if readcount=0 then signal(wmutex);
                            signal(rmutex);
                        until false; end
            writer: begin
                        repeat
                            wait(wmutex);
                            perform write operation; 
                            signal(wmutex);
                        until false; end
        parend 
    end

2. 利用信号量集机制解决读者—写者问题

这里的读者—写者问题与前面的略有不同,它增加了一个限制,即最多只允许 RN 个读 者同时读。为此,又引入了一个信号量 L,并赋予其初值为 RN,通过执行 wait(L,1,1) 操作,来控制读者的数目。每当有一个读者进入时,就要先执行 wait(L,1,1)操作,使 L 的值减 1。当有 RN 个读者进入读后,L 便减为 0,第 RN+1 个读者要进入读时,必然会因 wait(L,1,1)操作失败而阻塞。对利用信号量集来解决读者—写者问题的描述如下:

Var RN integer;
        L,mx: semaphore:=RN,1;
    begin 
        parbegin
            reader: begin 
                        repeat
                            Swait(L,1,1); 
                            Swait(mx,1,0);
                                ...
                            perform read operation;
                                ... 
                            Ssignal(L,1);
                        until false; 
                    end
            writer: begin 
                        repeat
                            Swait(mx,1,1;L,RN,0); 
                            perform write operation; 
                            Ssignal(mx,1);
                        until false; 
                    end
        parend end

其中,Swait(mx,1,0)语句起着开关的作用。只要无 writer 进程进入写,mx=1,reader 进 程就都可以进入读。但只要一旦有 writer 进程进入写时,其 mx=0,则任何 reader 进程就都无法进入读。Swait(mx,1,1;L,RN,0)语句表示仅当既无 writer 进程在写(mx=1),又无reader 进程在读(L=RN)时,writer 进程才能进入临界区写。

http://gurglessh.github.io/2016/04/12/经典进程的同步问题/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345

推荐阅读更多精彩内容

  • ** 本文摘自汤小丹主编《计算机操作系统》(第三版)2.3 进程同步 ** 在 OS 中引入进程后,虽然提高了资源...
    刘帅_阅读 3,088评论 0 0
  • 窗外下着小雨,听着音乐心情也略带烦躁。 生活虽然平淡但仍有些事情烦心,比如对上一段感情的不甘,对自己似悲剧像喜剧的...
    我是正版的猫啦阅读 255评论 0 0
  • (睡佛)一觉睡到自然醒,入梦不理天下事。笑吟三更君私语,埋床红袖添香时。半睡半醒游太虚,三生三世十里桃。多少笑梦桃...
    甘朝武阅读 303评论 0 0