经典进程的同步问题

记录型信号量定义

//用结构体定义一个记录型信号量,value是代表资源数目的整型变量,list为进程链表指针,用于链接所有等待该资源的进程
typedef struct{
    int value;
    struct process_control_block *list;
    }semaphore;

wait(semaphore *S)
{
    S->value--;
    if(S->value<0)
        block(S->list);//进程调用block原语进行自我阻塞,放弃处理机
}                      //并插入到信号量链表S->list中

signal(semaphore *S)
{
    S->value++;
    if(S->value<=0)     
        wakeup(S->list);//将S->list链表中第一个等待进程唤醒
}

生产者—消费者问题

问题

一组生产者进程和一组消费者进程共享一个初始为空、大小为n的缓冲区,只有缓冲区没满时,生产者才能把消息放入到缓冲区,否则必须等待;只有缓冲区不空时,消费者才能从中取出消息,否则必须等待。由于缓冲区是临界资源,它只允许一个生产者放入消息,或者一个消费者从中取出消息。

生产者与消费者全互斥

int in=0,out=0;
item buffer[n];
semaphore mutex=1,empty=n,full=0;
void producer()
{
    do{
        produce an item nextp;
        ...
        wait(empty);
        wait(mutex);
        buffer[in]=nextp;
        in=(in+1)%n;
        signal(mutex);
        signal(full);
        }while(TRUE);
}

void consumer()
{
    do
    {
        wait(full);
        wait(mutex);
        nextc=buffer[out];
        out=(out+1)%n;
        signal(mutex);
        signal(empty);
        consume the item in nextc;
        ...
        }while(TRUE);
} 

void main()
{
    cobegin
        producer();
        consumer();
    coend;
}

注意,在每个程序中的多个wait不可以颠倒顺序。

生产者、消费者内部互斥

对上面的代码稍作修改,引入两个mutex,分别控制生产者与消费者对buffer[n]的访问。

void producer()
{
    do{
        produce an item nextp;
        ...
        wait(empty);
        wait(mutex1);
        buffer[in]=nextp;
        in=(in+1)%n;
        signal(mutex1);
        signal(full);
        }while(TRUE);
}

void consumer()
{
    do
    {
        wait(full);
        wait(mutex2);
        nextc=buffer[out];
        out=(out+1)%n;
        signal(mutex2);
        signal(empty);
        consume the item in nextc;
        ...
        }while(TRUE);
} 

当缓冲区无限大时

基于全互斥,若缓冲区无限大,生产者生产的时候不需要等待缓冲区有空间,删除wait(empty),消费者中的signai(empty)也对应删除。

void producer()
{
    do{
        produce an item nextp;
        ...
        wait(mutex);
        buffer[in]=nextp;
        in=(in+1)%n;
        signal(mutex);
        signal(full);
        }while(TRUE);
}

void consumer()
{
    do
    {
        wait(full);
        wait(mutex);
        nextc=buffer[out];
        out=(out+1)%n;
        signal(mutex);
        consume the item in nextc;
        ...
        }while(TRUE);
} 

利用管程解决

首先建立一个管程。

Monitor producerconsumer
{
    item buffer[N];
    int in,out;
    condition notfull,not empty;
    int count;
    public:
    void put(item x)
    {
        if(count>=N)
            cwait(notfull);
        buffer[in]=x;
        in=(in+1)%N;
        count++;
        csignal(notempty);
    }
}

void get(item x)
{
    if(count<=0)
        cwait(notempty);
    x=buffer[out];
    out=(out+1)%N;
    count--;
    csignal(notfull);
}

{in=0;out=0;count=0;}

}PC;

void producer()
{
    item x;
    while(TRUE)
    {
        ...
        produce an item in nextp;
        PC.put(x);
    }
}

void consumer()
{
    item x;
    while(TRUE)
    {
        PC.get(x);
        consume the item in nextc;
        ...
    }
}

void main()
{
    cobegin
    producer();
    consumer();
    coend;
}

哲学家进餐问题

问题

哲学家就餐问题可以这样表述,假设有五位哲学家围坐在一张圆形餐桌旁,做以下两件事情之一:吃饭,或者思考。吃东西的时候,他们就停止思考,思考的时候也停止吃东西。餐桌中间有一大碗意大利面,每两个哲学家之间有一只餐叉。因为用一只餐叉很难吃到意大利面,所以假设哲学家必须用两只餐叉吃东西。他们只能使用自己左右手边的那两只餐叉。
用一个信号量表示一支筷子。

semaphore chopsticks[5]={1,1,1,1,1};

do{//描述某个哲学家的活动
    wait(chopsticks[i]);
    wait(chopsticks[i+1]%5);
    ...
    //eat
    ...
    signal(chopsticks[i]);
    signal(chopsticks[i+1]%5);
    ...
    //think
    ...
    }while(TRUE);

以上描述会引起死锁,可以采用一定的规则解决。如可以利用AND信号量解决。

semaphore chopsticks[5]={1,1,1,1,1};
do{
    ...
    //think
    ...
    Swait(chopsticks[i],chopsticks[i+1]%5);
    ...
    //eat
    ...
    Signal(chopsticks[i],chopsticks[i+1]%5);
    }while(TRUE);

读者—写者问题

问题

(1)允许多个读者同时执行读操作;
(2)不允许读者、写者同时操作;
(3)不允许多个写者同时操作。
Reader和Writer的同步问题分为读者优先、弱写者优先(公平竞争)和强写者优先三种情况,它们的处理方式不同。

读者优先

条件

对于读者优先,应满足下列条件:
如果新读者到:
①无读者、写者,新读者可以读;
②有写者等待,但有其它读者正在读,则新读者也可以读;
③有写者写,新读者等待。
如果新写者到:
①无读者,新写者可以写;
②有读者,新写者等待;
③有其它写者,新写者等待。

实现

int readcount=0;     //用于记录当前的读者数量  
semaphore rmutex=1;  //用于保护更新readcount变量时的互斥  
semaphore rwmutex=1; //用于保证读者和写者互斥地访问文件  
void Writer()
{//写者进程  
do{
    wait(rwmutex);
    perform write operation;
    signal(wmutex);
    }while(TRUE);
}

Reader()
{// 读者进程  
    do{
        wait(rmutex);
        if(readcount==0)
            wait(rwmutex);
        readcount++
        signal(rmutex);
        ...
        perform read operation;
        ...
        wait(rmutex);
        readcount--;
        if(readcount==0)
            signal(rwmutex);
        signal(rmutex);
        }while(TRUE);
}

void main()
{
    cobegin
    Reader();
    Writer();
    coend;
}  

若最多只允许RN个读者读,引入信号量L=RN,利用信号量集机制。

int RN;
semaphore L=RN,mx=1;
void Reader()
{
    do{
        Swait(L,1,1);
        Swait(mx,1,0);//开关作用,只要无写者进入,mx=1,reader随时可
        ...           //以进入读操作
        perform read operation;
        ...
        Ssignal(L,1);
        }while(TRUE);
}

void Writer()
{
    do{
        Swait(mx,1,1;L,RN,0);   //既无写者在写(mx=1)又无读者在读    
        perform write operation;//(L=RN)
        Ssignal(mx,1);
        }while(TRUE);
}

void main()
{
    cobegin
    Reader();
    Writer();
    coend;
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值