详细解读【互斥和同步】

本文详细介绍了互斥和同步的概念,包括原子操作、临界区、死锁、活锁、互斥和竞争条件。讨论了硬件在支持并发中的作用,如中断禁用和专用机器指令。重点讲述了信号量机制,包括二元信号量、互斥锁以及管程的原理和应用。此外,还分析了生产者/消费者问题、读者/写者问题,并提到了消息传递作为实现同步的一种方式。文章最后探讨了在具体实现中如何避免错误,强调了PV操作的原子性和不同情况下的调度策略。
摘要由CSDN通过智能技术生成

互斥和同步

这部分知识相对于后面的内存管理等要记忆的不多,主要是理解整个流程。

  • 原子操作/临界区(一段用于访问共享资源的代码,不允许多个进程同时访问)/死锁/活锁/互斥/竞争条件

  • 硬件的支持

    • 中断禁用:只适用与单处理器机器中,一个进程在调用一个系统服务或被中断之前将一直运行,因此并发进程不能重叠,只能交替。由系统内核为启用和禁用中断定义的原语提供。进入临界区启用中断。
    • 专用机器指令:执行期间任何其他指令访问内存都将被阻止,且这些动作在一个指令周期中完成
      • compare_and_swap:使用测试值testval
      • 忙等待/自旋等待:试图进入临界区的其他进程进入忙等待模式
    /* program mutualexclusion */
    const int n = /* number of processes */;
    int bolt;
    void P(int i)
    {
    	while (true) {
    	while (compare_and_swap(&bolt, 0, 1) == 1)
     		/* do nothing */;
    	/* critical section */;
    	bolt = 0;
    	/* remainder */;
    	}
    }
    void main()
    {
    	bolt = 0;
    	parbegin (P(1), P(2), . . . ,P(n));
    }
    /* program mutualexclusion */
    int const n = /* number of processes*/;
    int bolt;
    void P(int i)
    {
    	while (true) {
    	int keyi = 1;
    	do exchange (&keyi, &bolt)
    	while (keyi != 0);
    	/* critical section */;
    	bolt = 0;
    	/* remainder */;
    	}
    }
    void main()
    {
    	bolt = 0;
    	parbegin (P(1), P(2), . . ., P(n));
    

在这里插入图片描述

  • 信号量S:一个整型变量,除了初始化外只能通过原语wait()(P,荷兰语测试)和signal()访问(V,增加)

    信号量的初值为可用资源数量。当进程需要使用资源时,需要对该信号量执行 wait() 操作(减少信号量的计数)。当进程释放资源时,需要对该信号量执行 signal() 操作(增加信号量的计数)。当信号量的计数为 0 时,所有资源都在使用中。之后,需要使用资源的进程将会阻塞,直到计数大于 0。

    struct semaphore{//可用于控制访问具有多个实例的某种资源
        int count;
        queueType queue;
    };
    void semWait(semaphore s){//申请使用资源
        s.count--;//在此之前是无法提前知道该信号量是否会被阻塞的
        if(s.count<0){//==0表示当前进程可以使用最后一个空闲资源
            //把当前进程插入队列
            //阻塞当前进程
        }
    }
    void semSignal(semaphore s){//结束使用资源
        s.count++;
        if(s.count<=0){//原本至少是-1,至少有一个进程因等待而阻塞,则唤醒
            //把进程P从队列中移除
            //把进程P插入就绪队列
        }
    }
    

    解决同步问题的实例:现有两个并发运行的进程:P1 有语句 S1 而 P2 有语句 S2。假设要求只有在 S1 执行后才能执行 S2。我们可以轻松实现这一要求:让 P1 和 P2 共享同一信号量 synch,并且初始化为 0。

    //进程P1中插入语句
    S1;
    signal (synch);
    
    //在进程 P2 中,插入语句:
    wait (synch);
    S2;
    //因为 synch 初始化为 0,只有在 P1 调用 signal(synch) ,即 S1 语句执行之后,P2 才会执行 S2。
    
  • 二元信号量:只能是0/1

    struct binary_semaphore{//可用于控制访问具有多个实例的某种资源
        enum {zero,one} value;
        queueType queue;
    };
    void semWaitB(binary_semaphore s){//申请使用资源
        if(s.value==one)
        	s.value=zero;//被占领
        else{//已经被占领
            //把当前进程插入队列
            //阻塞当前进程
        }
    }
    void semSignalB(binary_semaphore s){//结束使用资源
        if(s.queue is empty())//没人等待
        	s.value=one;//标志当前资源空闲
        else{
            //把进程P从队列中移除
            //把进程P插入就绪队列
        }
    }
    
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值