十天玩转操作系统之信号量机制大盘解,简易理解,重点复习!!!


       操作系统(OS)这门学科在计算机领域有着很重要的作用,作为计算机硬件和软件的临界者,对计算机发展有着很重要的意义,随着时代的不断发展,越来越多的操作系统进入大众视野,无论是大家耳熟能详的Windows、MAC,抑或是程序员口中经常念叨的Linux。除了电脑操作系统,手机中的鸿蒙、苹果、安卓也是大家关注的热点,因此要想在计算机领域有所造诣,操作系统是必须要了解掌握的一门学科,因此在这里借助平台,跟大家分享一下我学习操作系统的经验和笔记,用十天的时间来和大家梳理和整理这门学科,让我们一起探索其中的奥秘,享受知识带给我们的快乐吧!!!

信号量机制

用户进程可以通过操作系统提供的一对原语来对信号量进程操作,从而方便实现进程互斥、进程同步。
信号量表示系统中某种资源的数量
一对原语:wait(S)原语和signal(S)原语,简称P(S)、V(S)操作
(1)整型信号量
用一个整数型的变量作为信号量,用来表示系统中某种资源的数量
“检查”和“上锁”一气呵成避免并发、异步导致的问题
存在问题:不满足“让权等待”原则,会发生“忙等”
(2)记录性信号量

typedef struct{
    int value;                    //剩余资源数
    Struct process *L;      //等待队列
}semaphore;

wait和signal原语实现系统资源的“申请”和“释放”
S.value的初值表示系统中某种资源的数目

void wait(semaphore S){
    S.value--;
    if(S.value<0){
        block(S.L);
}}

void signal(semaphore S){
    S.value++;
    if(S.value<=0){
        wakeup(S.L);
}}

信号量机制实现进程互斥

1、分析并发进程的关键活动 ,划定临界区
2、设置互斥信号量mutex,初值为1

/*信号量机制实现互斥*/
semaphore mutex=1;    //初始化信号量

p1(){
    ...
    p(mutex);        //使用临界资源前需要加锁
    临界区代码段..
    V(mutex);        //使用临界资源后需要解锁
    ...
}

p2(){
    ...
    P(mutex);
    临界区代码段
    V(mutex);
    ...
}

P、V操作必须成对出现。缺少P(mutex)不能保证临界资源的互斥访问,缺少V(mutex)导致资源永不被释放

信号量机制实现进程同步

1、分析“同步关系”的需求,保证执行顺序
2、设置同步信号S,初始值为0
3、在“前操作”之后执行V(S)
4、在“后操作”之前执行P(S)

/*信号量机制实现同步*/
semaphore S=0;    //初始化同步信号量,初始值为0

p1(){
    代码1;
    代码2V(S)//S++
    代码3}

p2(){
    P(S)//S--
    代码4;
    代码5;
    代码6}

信号量机制实现前驱关系

1、为每一对前驱关系设置同步信号量,初值为0
2、在“前操作”之后执行V(S)
3、在“后操作”之前执行P(S)


了解完信号量机制之后,我们需要理解操作系统在进程切换等情况中信号量机制的作用和用法,了解完基础概念之后,我们需要考虑的便是常见的几种处理问题的方式,分析其伪代码,洞悉其中的思想,分析利弊,便于自己更加深刻理解进程与线程的知识,脑海中要有一定的框架结构!!


常见问题及其伪代码

生产者消费者问题

生产者、消费者共享一个初始值为空、大小为n的缓冲区

  • 只有缓冲区没满时,生产者才能把产品放入缓冲区,否则必须等待。
  • 只有缓冲区不空时,消费者才能从中取出产品,否则必须等待
  • 缓冲区时临界资源,各个进程必须互斥地访问

互斥信号量是1,同步信号量依题意设置

semaphore mutex=1;        //互斥信号量,实现对缓冲区的互斥访问
semaphore empty=n;        //同步信号量,表示空闲缓冲区的数量
semaphore full=0;              //同步信号量,表示产品的数量,也即非空缓冲区的数量

producer()
{
    while(1){
        生产一个产品;
        P(empty);                //消耗一个空闲缓冲区
        P(mutex);
        把产品放入缓冲区;
        V(mutex);
        V(full);                    //增加一个产品
    }
}

consumer(){
    while(1){
        P(full);                        //消耗一个产品(非空缓冲区)
        P(mutex);
        从缓冲区取出一个产品;
        V(mutex);
        V(empty);                //增加一个空闲缓冲区
        使用产品;
    }
}

多生产者消费者问题

semaphore mutex=1;            //实现互斥资源访问盘子
semaphore apple=0;             //盘子有几个苹果
semaphore orange=0;           //盘子有几个橘子
semaphore plate=1;               //盘子还可以盛放多少个水果

dad(){
    while(1){
        准备一个苹果;
        P(plate);
        P(mutex);
        把苹果放入盘子;
        V(mutex);
        V(apple);
    }
}

mom(){
    while(1){
        准备一个橘子;
        P(plate);
        P(mutex);
        把橘子放入盘子;
        V(mutex);
        V(apple);
    }
}

daughter(){
    while(1){
        P(apple);
        P(mutex);
        从盘子取出苹果;
        V(mutex);
        V(plate);
        吃掉苹果;
    }
}

son(){
    while(1){
        P(orange);
        P(mutex);
       从盘子中取出橘子;
        V(mutex);
        V(plate);
       吃掉橘子
    }
}

缓冲区>1的情况,必须要设置互斥信号量,否则会造成数据覆盖的情况。

吸烟者问题

provider(){
    while(1){
       if(i==0){
            将组合一放桌上;
            V(offer1);
    }else if(i==1){
            将组合二放桌上;    
            V(offer2);
    }else if(i==2){
            将组合一放桌上;
            V(offer3);
    }
     i=(i+1)%3;
    P(finish);
    }
}

semaphore offer1=0;        //桌子组合一的数量
semaphore offer2=0;        //桌子组合二的数量
semaphore offer3=0;        //桌子组合三的数量
semaphore finish=0;        //抽烟是否完成从
int i=0;                                //用于实现“三个抽烟者轮流抽烟”

smoker1(){
    while(1){
        P(offer1);
        从桌子上取走组合一;
       卷烟、抽掉;
        V(finsh);
    }
}

smoker2(){
    while(1){
         P(offer2);
         从桌子上取走组合二;
        卷烟、抽掉;
        V(finsh);
    }
}

smoker3(){
    while(1){
         P(offer3);
        从桌子上取走组合三;
        卷烟、抽掉;
        V(finsh);
    }
}

读者写者问题

1、允许多个读者可以同时对文件执行读操作
2、只允许一个写者往文件中写信息
3、 任一写者在完成写操作之前不允许其他读者或写者工作
4、写者执行前,应让己有的读者和写者全部退出

semaphore rw=1;        //用于实现对文件的互斥访问。表示当前是否有进程在访问共享文件
int count=0;           //记录当前有几个读进程在访问文件
semaphore mutex=1      //用于保证对count变量的互斥访问
semaphore w=1;         //优先实现“写优先”

writer(){
    while(1){
        P(w);
        P(rw);         //写之前“加锁”
        写文件……
        V(rw);        //写之后“解锁”
        V(w);
    }
}

reader(){
    while(1){
        P(w);
        P(mutex);        //各个进程互斥访问count
        if(count==0P(rw);       //第一个读进程负责“加锁”
        count++;
        V(mutex);
        V(w);
        读文件……
        P(mutex);      //各个进程互斥访问count
        count--;        //访问文件的读进程数-1
        if(count==0)
            V(rw);       //最后一个读进程负责“解锁”
        V(mutex);        
    }
}

哲学家问题

死锁情况:

semaphore chopstick[5]={1,1,1,1,1};
Pi(){    //i号哲学家的进程
    while(1){
        P(chopstick[i]);                //拿左
        P(chopstick[(i+1)%5];    //拿右    
        吃饭……
        V(chopstick[i]);               //放左
        V(chopstick[(i+1)%5];    //放右    
        思考……
    }
}
谁也不让谁,都不放弃手上资源,都被饿死……

解决方案:

semaphore chopstick[5]={1,1,1,1,1};
semaphore mutex=1;        //互斥取筷子
Pi(){    //i号哲学家的进程
    while(1){
        P(mutex);
        P(chopstick[i]);                //拿左
        P(chopstick[(i+1)%5];            //拿右
        V(mutex);    
        吃饭……
        V(chopstick[i]);               //放左
        V(chopstick[(i+1)%5];    //放右    
        思考……
    }
}

      第四天的学习到这里就结束了,不知道小伙伴们收获如何呢?欢迎评论区交流学习,也恳请各位批评指正!!

      操作系统其实就是计算机中的一个大管家,这个大管家有着很多很厉害的角色(就像谍战片里面的大府中的老管家一样),因此学习操作系统这门课,就像是在欣赏一部谍战片,要想理解角色内涵,你就必须站在其角度去思考,思考其可能会遇到的危险以及应对策略(bug与bug的修复),这样你才能在凶险的代码江湖生存下来,成为一代英雄,留下你的印记,期待与各位在江湖的相遇,也希望大家能给作品一个三连!!


本文参考教材:王道考研——操作系统(配套PDF文件,点赞留言后私信我发你)
教材配套讲解视频:b站链接


  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

柠笙

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

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

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

打赏作者

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

抵扣说明:

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

余额充值