操作系統-PV習題


(1)閱覽室問題:加入閱覽室入口有一本登記冊,每個人都必須按順序簽名進去。

想法:登記冊可以用結構數組A[]表示,包含name和number。此外,還需要信號量seatcount表示剩余座位數。
使用信號量mutex約束每次只有一個人能修改登記冊
struct { 
    char name[10]; 
    int number;
}A[100];
semaphore mutex = 1; //控制A[]被修改的信號量
semaphore seatcount = 100; //剩余的座位數
int i;
for(i=0; i<100; i++) {
    A[i].number=i;
    A[i].nume=null;
}
cobegin
process readeri(char readername[]) {
    P(seatcount);
    P(mutex);
    for(int i=0; i<100; i++) {
        if(A[i].name==null) A[i].name=readername;
        reader get the seat number i;
    }
    V(mutex);
    {進入閱覽室座位號i,坐下讀書};
    P(mutex);
    A[i].name = null;
    V(mutex);
    V(seatcount);
}
coend
(2)四個進程Pi(i=0…3)和四個信箱Mj(j=0…3),進程間借助相鄰信箱傳遞消息,即Pi每次從Mi中取一條消息,經加工后送入M(i+1)mod4,其中M0、M1、M2、M3分別可存放3、3、2、2個消息。初始狀態下,M0裝了三條消息,其余為空。試以P、V操作為工具,寫出Pi(i=0…3)的同步工作算法。
想法:說穿了還是有緩沖區的生產者消費者問題,每個信箱需要用信號量empty表示剩余空間、full表示剩余信件。此外還需要int數in、out指明信箱中存取信的位置,以及對應信號量mutex。
semaphore mutex1 = mutex2 = mutex3 = mutex0 = 1; //約束每個信箱同一時間只能有一個進程操作
semaphore empty0 = 0 , empty1 = 3 , empty2 = empty3 =2; //信箱剩余空間
semaphore full0 = 3 , full1 = full2 = full3 =0; //信箱剩余信件數
int in0 = in1 = in2 = in3 = out0 = out1 = out2 = out3 =0; //信箱中存、取信的位置,初始均為0
cobegin
process P0( ) {
    while(true) {
        P(full0);
        P(mutex0);
        {從M0[out0]取一條消息};
        out0 = ( out0 + 1 ) % 3;
        V(mutex0);
        V(empty0);
        {加工消息};
        P(empty1);
        P(mutex1);
        {消息存M1[in1]};
        in1 = ( in1 + 1 ) % 3;
        V(mutex1);
        V(full1);
    }
}
/*P1-P3略*/
coend    
(3)今有k個進程,它們的標號依次為1~k,如果允許它們同時讀文件file,但必須滿足條件:參加同時讀文件的進程的標號之和需小於M(k<M)
想法:用一個數numbersum記錄當前讀文件的進程標號之和,通過信號量mutex實現對其的互斥操作
如果進程發現自己不能運行,就要P(waits)把自己阻塞,阻塞后因為其還在numbersum的臨界區內,因此其它進程也進不來了;每當讀文件完成,釋放一個等待的進程;被釋放的進程再次檢測自己能否運行,不能的話繼續P(waits)把自己阻塞
semaphore waits = 0;
Semaphore mutex = 1;
int numbersum = 0;
cobegin
process readeri(int number) {    
    P(mutex);
    while(numbersum+number>=M) {
        V(mutex);
        P(waits);
    }
    numbersum = numbersum + number;
    V(mutex);
    Read file;
    P(mutex);
    numbersum = numbersum - number;
    V(waits); 
    V(mutex);
}
coend
(5)輪流撿黑、白棋子:其實就是最簡單的生產者消費者問題
semaphore s1 = 1; //可撿白子
semaphore s2 = 0; //可撿黑子
process p1() {
    while(true) {
        P(s1);
        撿白子;
        V(s2);
    }
}
process p2() {
    while(true) {
        P(s2);
        撿白子;
        V(s1);
    }
}
南大13年真題:A撿黑子並計數,B撿白子並計數。不要求輪流撿,但要求互斥撿。C等待AB完成后,合計計數。
想法:通過互斥信號量mutex實現A和B互斥撿棋子。計數器則不需要互斥,因為黑子、白子是分兩個計數器;A和B計數完成后各自V(allow),從而允許C工作
Semaphore allow = -1;
Semaphore mutex = 1;
int count = count_black = count_black = 0;
process A(){
    while(true){
        P(mutex);
        get(black);
        V(mutex);
        if(取到了){count_black++;}
        else break;
    }
    V(allow);
} 
process B(){
    while(true){
        P(mutex);
        get(write);
        V(mutex);
        if(取到了){count_write++;}
        else break;
    }
    V(allow);
}
process C(){
    P(allow);
    count = count_black + count_write;
    printf();
}
(6)n1個進程通過m個緩沖區向n2個緩沖區發消息,每條消息n2個接收進程都要各自接收一次。
思路:課本答案的做法是把這一組緩沖區看成n2組緩沖區(每組m個),每個發送進程需要同時寫n2個緩沖區。但是我覺得答案做法很迷啊,m個緩沖區直接被它強行變成了n2*m個緩沖區,每次寫一個、接收n2次,變成了每次寫n2個、接收n2次。而且答案明明把緩沖區分為n2組,但是只有一個信號量mutex實現對緩沖區操作的互斥。
semaphore mutex , empty[n2] , full[n2];
int i;
mutex = 1;
for(i=1; i<n2; i++) {
    empty[i]=m;
    full[i]=0;
}
cobegin
send() {           
    for(int i=0;i<n2;i++) {
        P(empty[i]);
        P(mutex);
        {將消息放入緩沖區;}
        V(mutex);
    }
    for(int i=0;i<n2;i++){
        V(full[i]);
    }
}
receive() {       
    for(int i=0;i<n2;i++) {
        P(full[i]);
        P(mutex);
        {從緩沖區中取出信息;}
        V(mutex);
    }
    for(int i=0;i<n2;i++) {
        V(empty[i]);
    }
}
coend
(7)生產者進程每次寫3個緩沖區,消費者進程每次讀一個緩沖區
思路:答案的思路是通過信號量s1控制每次只允許一個生產者寫,通過信號量s2控制每次只允許一個消費者讀。因此本題生產者和消費者可以同時工作。
定義了一個初始為0的int數count,每次消費都將其加1,每三次消費之后count達到3,才V(sput)一次,允許一次生產;每次生產之后進行三次V(sget)允許三次消費。
int buf[9];
int count = getptr = putptr = 0;
semaphore s1 = s2 = 1;
Semaphore sput = 1;
Semaphore sget = 0;
cobegin
process producer_i() {
    while(true) {
        P(sput);
        P(s1);
        buf[putptr] = 1;
        putptr = ( putptr + 1 ) % 9;
        buf[putptr] = 2;
        putptr = ( putptr + 1 ) % 9;
        buf[putptr] = 3;
        putptr = ( putptr + 1 ) % 9;
       V(sget);
        V(sget);
        V(sget);
        V(s1);        
    }
}
process consumer_j() {
    int y;
    while(true) {
       P(sget);
        P(s2);
        y = buf[getptr];
        getptr = ( getptr + 1 ) % 9;
        count++;
        if(count==3){
            count = 0;
           V(sput);
        }
        V(s2);
        消費整數y;
    }
}
coend
(8)有三組工人和N個槽,第一組工人生產車架,第二組工人生產車輪,第三組工人用車架和四個車輪生產一輛車
思路:其實就是上一題的生產者消費者問題的加強版,可以把N個槽分為N/5、4N/5兩部分,分別裝車架和車輪,否則可能會出現裝滿車架或車輪的情況。
通過信號量mutex1控制每次只有一個進程操作第一個槽(即只有1個生產者放車架或1個消費者拿車架);通過mutex2控制每次只有一個進程操作第二個槽(即只有一個生產者放車輪或1個消費者拿車輪)。
每生產一個車架就可以直接拿(不需要像車輪那樣通過計數器count控制),因此每次生產一個車架都V(s3)一次。
每生產四個車輪才能拿一次,因此定義了一個初始為0的int數count,每次生產車輪都將其加1,count達到4時才V(s4)一次。因為有mutex2的存在,因此每次只有一個進程能修改count。
semaphore mutex1 = mutex2 = 1;
semaphore s1 = N/5 , s2 = 4N/5 , s3 = s4 = 0;
int count = 0;
int in1 = in2 = out1 = out2 = 0;
cobegin
process worker1() {
    while(true) {
        加工一個車架;
        P(s1);
        P(mutex1);
        車架放入box[in1];
        in1 = (in1 +1) % (N/5);
        V(mutex1);
        V(s3);
}
process worker2() {
    while(true) {
        加工一個車輪;
        P(s2);
        P(mutex2);
        車架放入box[in2];
        in2 = (in2 +1) % (4N/5);
        count = count + 1;
        if(count==4) {
            count = 0;
            V(s4);
        }
        V(mutex2);
}
process worker3() {
    while(true) {
        P(s3);
        P(mutex1);
        從box[out1]拿車架;
        out1 = (out1 + 1) % (N/5);
        V(mutex1);
        V(s1);
        P(s4);
        P(mutex2);
        從box[out2]開始取四個車輪;
        out2 = (out2 + 4) % (4N/5);
        V(s2);
        V(mutex2);
        裝配車子;
    }
}
ceend
(9)有一個倉庫,可存放X、Y兩種產品,倉庫的存儲空間足夠大,但要求:(1) 每次只能存入一種產品X或Y, (2) 滿足-N<X-Y<M
想法:可以設置兩個信號量來控制X、Y產品的存放數量關系:
sx表示當前允許X產品比Y產品多入庫的數量,即在當前庫存量和Y產品不入庫的情況下,還可以允許sx個X產品入庫,初始時,若不放Y而僅放X產品,則sx最多為M-1個;
sy表示當前允許Y產品比X產品多入庫的數量,即在當前庫存量和X產品不入庫的情況下,還可以允許sy個Y產品入庫,初始時,若不放X而僅放Y產品,則sy最多為N-1個。
當往庫中存放入一個X產品時,則允許存入Y產品的數量也增加1,故信號量sy應加1;當往庫中存放入一個Y產品時,則允許存入X產品的數量也增加1,故信號量sx應加1。
semaphore mutex=1;         
semaphore sx = M-1;
semaphore sy = N-1;
cobegin
process storeX( ) {
    while(true) {
        P(sx);
        P(mutex);
       {將X產品入庫};
       V(mutex);
        V(sy);
    }
}
process storeY( ) { 
    while(true) {
       P(sy);
       P(mutex);
       {將Y產品入庫};
       V(mutex);
       V(sx);
    }
}
coend
(10)有一個倉庫,可放入A、B兩種產品,最大庫容量各為m個,生產車間不斷地取A、B進行裝配,每次各取一個。為了零件腐蝕,必須按照先入庫者先出庫的順序。有兩組供應商分別不斷地供應A和B,每次一個。為了保證配套和庫存合理,當某種零件比另一種超過n個時,暫停對數量大的零件的進貨。
想法:這題實際是上一題的強化版,按照題意一共四種約束關系:0≤A≤m、0≤B≤m、B-A≤n、A-B≤n,分別通過信號量empty1、full1、empty2、full2、sa、sb進行控制。
答案是通過mutex約束每次只有一個進程操作倉庫。其實也可以把約束條件放得更寬泛些。
semaphore empty1 , empty2 , full1 , full2 , mutex , sa , sb;
int in1 , in2 , out1 , out2;
empty1 = empty2 = m; //剩余可放空間
full1 = full2 = 0; //剩余產品數
sa = sb = n;
mutex = 1;
in1 = in2 = out1 = out2 = 0;
cobegin
process put_A() {
    while(true) {
        P(empty1);
        P(sa);
        P(mutex);
        把A零件放入buffA[in1];
        in1 = (in1 + 1) % m;
        V(mutex);
        V(sb);
        V(full1);
    }
} 
process put_B() {
    while(true) {
        P(empty2);
        P(sb);
        P(mutex);
        把B零件放入buffB[in2];
        in2 = (in2 + 1) % m;
        V(mutex);
        V(sa);
        V(full2);
    }
} 
process get() {
    while(true) {
        P(full1);
        P(full2);
        P(mutex);
        從buffA[out1]取A零件;
        從buffB[out2]取B零件;
        out1 = (out1 + 1) % m;
        out2 = (out2 + 1) % m;
        V(mutex);
        V(empty1);
        V(empty2);
        把A和B裝配成產品;       
    }
}
coend
因為裝配時A和B各取一件,所以對它們的相對關系並無影響,因為無需對信號量sa和sb進行修改。
答案用了信號量mutex約束三個進程不能同時工作,其實我覺得應該改用三個信號量。
(11)能容納500人的博物館,每次只能一個人進出
思路:使用mutex約束每次只有一個人使用門。本題必須注意,進門與出門操作必須在P(empty)和V(empty)之間的臨界區內,即有空位才能進門,出門后才釋放空位
Semaphore empty = 500;
Semaphore mutex = 1;
cobegin
process_i(){
    P(empty);
    P(mutex);
    進門;
    V(mutex);
    參觀;
    P(mutex);
    出門;
    V(mutex);
   V(empty);
}
(12)三個線程增加互斥條件
typedef struct{
    float a;
    float b;
}cnum;
cnum x , y ,z;
cnum add(cnum p ,cnum q){
    cnum s;
    s.a = p.a + q.a;
    s.b = s.b + q.b;
    return s;
}
想法:本題先看代碼,thread1和thread2會修改w,但是w是它們自身創建的,其它線程也沒有使用到;而thread3則修改了z、y;
thread3會修改z,而thread2會訪問z,必須定義信號量使它們互斥訪問z;
thread3會修改y,而thread1和thread2都會訪問y,因此需要定義互斥信號量mutex_y1使thread1和thread3對y互斥訪問、定義互斥信號量mutex_y2使thread2和thread3對y互斥訪問(thread2和thread3不需要互斥y)
Semaphore mutex_y1 = 1;  //線程1、3對y的互斥訪問
Semaphore mutex_y2 = 1;  //線程2、3對y的互斥訪問
Semaphore mutex_z = 1;   //線程2、3對z的互斥訪問
 
thread1{
    cnum w;
    P(mutex_y1);
    w = add(x , y);
    V(mutex_y1);
}    
thread2{
    cnum w;
    P(mutex_y2);
    P(mutex_z);
    w = add(y , z);
    V(mutex_z);
    V(mutex_y2);
}    
thread3{
    cnum w;
    w.a = 1;
    w.b = 1;
    P(mutex_z);
    z = add(z , w);
    V(mutex_z);
    P(mutex_y1);
    P(mutex_y2)
    y = add(y , z);
    V(mutex_y1);
    V(mutex_y2);
}    
(13)14年南大真題:緩沖區可放2000字節,P進程讀入數據到緩沖區,Q1、Q2從緩沖區取數據並計算加工,並把結果打印出來。
題目給的子程序:read20()從輸入設備讀20個字數據到緩沖區;
                             get20()從緩沖區取20字節;
                             comp40t30()計算加工40個字得到結果30字節;
                             print15()打印15字節
Semaphore mutex = 1;
Sempahore full = 1;
Semaphore empty = 100;
process P(){
    P(empty);
    P(mutex);
    read20();
    V(mutex);
    V(full);
}
Process Q1(){
    P(full); get20();
    P(full); get20();
    comp40t30();
    V(empty); print15;
    V(empty); print15;
}
 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM