计算机操作系统(复习)同步与通信

基本概念

进程的互斥:由于竞争使用同一共享资源而产生相互制约的关系(间接制约关系)

进程的同步:进程之间通过在执行时序上的某种限制而达到相互合作的约束关系(直接制约关系)

临界资源:以互斥方式使用的共享资源,一次只允许一个进程使用(eg:打印机、磁带机)

进入区:申请进入临界区的那段代码

临界区:进程中访问临界资源的那段代码

退出区:退出对临界区访问的那段代码

剩余区:除进入区、临界区、退出区之外的代码

互斥准则:

  1. 空闲让进
  2. 忙则等待
  3. 有限等待
  4. 让权等待(当一个进程不能进入临界区时要立即阻塞自己,释放处理机让其他进程使用,避免“忙等”)

硬件同步机制

测试与设置指令(Test_and_Set)

交换指令(Exchange)

信号量机制

信号量机制由一个称为信号量的特殊变量和两个被命名为P操作( wait() )V操作( signal() )的原语组成。

信号量:若一个资源被视为临界资源时,为它定义一个独立的信号量

P操作:当一个进程需要互斥使用某个临界资源时,执行对信号量的该操作,了解资源的空闲情况

V操作:当使用完该临界资源后,执行信号量的该操作,让其他需要使用该资源的进程感知到该临界资源已经可以使用

整形信号量——未遵循让权等待的原则

记录型信号量

//信号量定义

typedef struct{
    int count;    //信号量的值,>0:资源的数量;<0:|S.count|表示等待此资源的进程数目
    queueType *queue;    //信号量等待队列指针
}semaphore;
// wait(S)操作

semaphore S;

void wait(S)
{
    S.count--;
    if(S.count<0){
        block(S.queue);    //阻塞该进程
        链接到S.queue队列;
    }
}
//signal(S)操作

void signal(S)
{
    S.count++;
    if(S.count<=0) wakeup(S.queue);    //从S.queue队列中移除一个进程,把该进程链接到就绪队列
}

信号量用于互斥

//任一进程Pi的框架

void Pi()
{
    semaphore mutex=1;
    do{
        wait(mutex);
        critical section;    //临界区
        signal(mutex);
        remainder section;    //剩余区
    }while(true);
}

信号量用于同步

例:有两个并发进程P1和P2,共享一个公共信号量S,初值为0。P1执行的程序中有一条S1语句,P2执行的程序中有一条S2语句。而且,只有当P1执行完S1语句后,P2才能开始执行S2语句。

semaphore S=0;    //信号量初值为0

//进程P1程序框架
void P1()
{
    ...
    S1;
    signal(S);
    ...
}

//进程P2程序框架
void P2()
{
    ...
    wait(S);
    S2;
    ...
}

void main()
{
    Parbegin(P1(),P2());    //Parbegin:挂起主程序,初始化并发进程P1和P2
}

经典进程同步问题

生产者-消费者问题

问题描述:有若干生产者进程在生产产品,假设生产者进程为k(k>0)个,并将这些产品提供给m( m>0)个消费者进程去消费。

问题求解:为使生产者进程与消费者进程能并发执行,在两者之间设置了一个具有n个缓冲区的缓冲池(假设组织成环形),生产者进程将所生产的产品放入缓冲区中;消费者进程可从一个缓冲区中取出产品。假定它们的约束条件有以下4个:

  1. 当缓冲池中有空缓冲区时,允许任一生产者进程把产品放入。
  2. 当缓冲池中无空缓冲区时,则试图将产品放入缓冲区的任何生产者进程必须等待。
  3. 当缓冲池中有产品时,允许任一个消费者进程把其中的一个产品取出消费。
  4. 当缓冲池中没有产品时,试图从缓冲池内取出产品的任何消费者进程必须等待。

问题分析:对所有生产者和消费者进程来说,可以把缓冲池视为一个整体,缓冲池是临界资源,即任何一个进程在对缓冲池中某个缓冲区进行“放入”放“取出”操作时必须和其他进程互斥执行。下面用信号量机制解决这个问题,首先定义信号量如下:

  1. 信号量mutex,初值为1,用于控制互斥地访问缓冲池。
  2. 信号量full,初值为0,用于资源计数。full 值表示当前缓冲池中“满”缓冲区的个数。
  3. 信号量empty,初值为n,用于资源计数。empty 值表示当前缓冲池中“空”缓冲区的个数。

伪代码呈现

const int n;    //buffer size
int in, out=0;    //缓冲区首空、首满指针
semaphore empty=n;
semaphore full=0;
semaphore mutex=1;

void producer()
{
    while(true){
        生产一个产品;
        wait(empty);
        wait(mutex);
        将产品放入缓冲区;
        in = (in+1)%n;
        signal(mutex);
        signal(full);
    }
}

void consumer()
{
    while(true){
        wait(full);
        wait(mutex);
        从缓冲区中取产品;
        out = (out+1)%n;
        signal(mutex);
        signal(empty);
        消费该产品;
    }
}

void main()
{
    parbegin( producer(), consumer() );
}

注:wait()和signal()不能互换

读者-写者问题

问题描述:有一个数据区(数据区可以是一个文件、一块内存空间或一组寄存器)被多个用户共享,其中一部分用户是读者,另一部分是写者。我们规定:读者对数据区是只读的,而且允许多个读者同时读;写者对数据区是只写的,当一个写者正在向数据区写信息的时候,不允许其他用户使用。即保证一个写者进程必须与其他进程互斥地访问共享对象。

问题求解:必须满足的条件如下:

  1. 任意多个读者可以同时读
  2. 任一时刻只能有一个写者可以写
  3. 如果写者正在写,那么读者就不能读

 将数据区访问的程序视为临界区。但是,数据区不是绝对的临界资源,因为它允许多个读者用户同时使用。因此,该问题有两种解决方案。

读者优先:读者优先是指一旦有一个写者访问数据区,只要还有一个读者在进行读操作,后续的读者就不需要等待,可以保持对数据区的控制,而写者必须等待所有的读者读完才可以进行写操作。

问题分析

  1. 使用一个互斥信号量wmutex,实现读者与写者、写者与写者之间的互斥。由于读者可以同时访问数据区,因此我们让第一 一个准备进入临界区的读者,通过wait(wmutex)强占临界资源,以便排斥写者访问。当最后一个读者离开临界区时,通过signal(wmutex)将临界资源释放,以便其他用户使用。
  2. 设计一个专为读者共享的变量readcounter,用来记录读数据区的人数。readcounter应视为临界资源,故应有一个互斥信号量,定义为rmutex。
     

伪代码呈现

int readcounter;
semaphore wmutex=1;
semaphore rmutex=1;    //对readcounter的互斥访问

void reader()
{
    while(true){
        wait(rmutex);
        readcounter++;
        if(readcounter==1) wait(wmutex);
        signal(rmutex);

        readunit();
        
        wait(rmutex);
        readcounter--;
        if(readcounter==0) signal(wmutex);
        signal(rmutex);
    }
}

void writer()
{
    while(true){
        wait(wmutex);

        readunit();
        
        signal(wmutex);
    }
}

void main()
{
    readcounter = 0;
    par begin( reader(), writer() );
}

写者优先只要有写者申请写操作,就不允许新的读者访问数据区。
问题分析:在前面定义的基础上,写者优先的解决方法增加了以下的信号量和变量:

  1. 信号量rsem用于在有写者访问数据区时,屏教所有的读者
  2. 变量writecount控制rsem的设置
  3. 信号量y控制writecount的修改

除此之外。对于读进程,还必须添加一个额外的信号量z。因为在rsem上不允许多于一个进程在排队, 否则写进程将不能跳过这个队列。因此只允许一个读进程在rsem上排队,而所有其他读进程在等待rsem之前,在信号量z上排队。下表 总结了写者优先方法中进程队列的各种情况。

队列状态操作
系统中只有读者设置信号量wsem;没有排队
系统中只有写者设置信号量wsem和rsem;写者在信号量wsem上排队
存在读者和写者且读者优先读者设置信号量wsem;写者设置信号量rsem;所有的写者在wsem上排队;只有一个读者在rsem上排队,其他读者在信号量z上排队
存在读者和写者且写者优先读者设置信号量wsem;写者设置信号量rsem;写者在wsem上排队;只有一个读者在rsem上排队,其他读者在信号量y上排队

伪代码呈现

int readcount, writecount;
semaphore x=1, y=1, z=1, wsem=1, rsem=1;

void reader()
{
    while(true){
        wait(z);
        wait(rsem);

        wait(x);
        readcount++;
        if(readcount==1) wait(wsem);
        signal(x);
        signal(rsem);
        signal(z);
        
        readunit();

        wait(x);
        readcount--;
        if(readcount==0) signal(wsem);
        signal(x);
    }
}

void writer()
{
    while(true){
        wait(y);
        writecount++;
        if(writecount==1) wait(rsem);
        signal(y);

        wait(wsem);
        writeunit();
        signal(wsem);

        wait(y);
        writecount--;
        if(writecount==0) signal(rsem);
        signal(y);
    }
}

void main()
{
    readcount = writecount = 0;
    parbegin( reader(), writer() );
}

哲学家就餐问题(略)

参考:《计算机操作系统》电子工业出版社

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cancri e

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值