zoukankan      html  css  js  c++  java
  • 并发实现机制-2-互斥实现

    并发核心问题是对资源的互斥需求,互斥的实现有多种方法(硬件方法和软件方法)

    互斥的方法

    1. 专用机器指令,较少开销但不通用。(硬件支持)
    2. 操作系统或程序设计语言提供某种级别的支持。(软件方法:操作系统和程序设计语言的支持)
    3. 进程承当实现互斥的责任,这是软件方法,增加了开销并存在缺陷。(软件方法:进程承担责任)

    其中方法1的几种实现有:中断禁用、专用机器指令;2的几种方法有:信号量、管程、消息传递等;方法3的几种实现有Dekker算法、Peterson算法、竞争条件和信号量等。这几种方法的详细说明将在本篇文章总结。

    硬件支持

    硬件实现的几种方法有:中断禁用,专用机器指令

    中断禁用:只需要保证一个进程不被中断即可,通过内核提供启用中断和禁用中断的原语来支持,但是代价很高,执行的效率会明显降低,另外不适用于多处理器

    专用机器指令:compare and swap指令,用一个测试值(testval)检查一个内存单元(*word)。如果这个内存单元的当前值是测试值(testval),就用新的值(newval)替换该值,否则保持不变。(当word为0可以进入临界区,出临界区把word重置为0,如果当前有一个进程在访问临界区,其他进程的testval是1,compare and swap返回的是1,如果没有任何进程在临界区,testval为0,compare and swap返回的是0,如果检查到返回的值和传入的testval不相等,说明word的值在上一次循环被更改),当有进程处于临界区时,其他进程处于忙等待(自旋等待),

    机器指令只解决了互斥,可能饥饿(选择进入临界区的进程是任意的)和死锁(如果P1在临界区被中断、并且P1在临界区正在持有一个资源R的访问,那么如果P2此时被调度执行并且试图访问R时就会失败,如果P2比P1的优先级高,P1永远不会被执行,P2永远处于忙等待,陷入死锁)

    软件方法:操作系统/程序语言支持

    todo: 表5.3 一般常用的并发机制截图

    信号量 semaphore

    二元信号量 binary semaphore,值只能是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插入就绪队列*/       
        }
    }
    

    计数信号量counting semaphore(一般信号量 general semaphore)

    struct semaphore{
        int count;
        queueType queue;
    }
    void semWait(semaphore s){
        s.count--;
        if(s.count<0){
            /*把当前进程插入队列*/
            /*阻塞当前进程*/
        }
    }
    void semSignal(semaphore s){
        s.count++;
        if(s.count<=0){
            /*把进程P从队列移除*/
            /*把进程P插入就绪队列*/
        }
    }
    

    信号量解决互斥问题的写法如下

    const int n= /*进程数*/;
    semaphore s = 1;
    void p(int i){
        while(true){
            semWait(s);
            /*临界区*/
            semSiganl(s);
            /*其他部分*/
        }
    }
    void main(){
        parbegin(P(1),P(1),...,P(n));
    }
    

    信号量的实现

    semWait和semSignal的实现必须是原子原语,任何时候只有一个进程可用semWait或者semSignal操作控制一个信号量。

    可以使用软件方案:dekker算法或者peterson算法,但这有处理开销

    可以使用硬件方案:comapare&swap和中断禁用(单处理器系统),因为semWait和semSignal的操作时间很短,因此忙等待或者中断禁用的时间都分长短,是比较合理的。

    实现方法如下(注意important语句,并注意堵塞进程时的处理,因为堵塞进程时进程无法到达最后一句,所以堵塞时就应该执行flag置为0或者允许中断!!!)

    void semWait(semaphore s){
        while(compare and swap(s.flag,0,1)==1); // important ! 或: 中断禁用
        s.count--;
        if(s.count<0){
            /*把当前进程插入队列*/
            /*阻塞当前进程,并设置flag为0或允许中断*/ // important !
        }
        s.flag=0; // important ! 或: 中断允许
    }
    void semSignal(semaphore s){
        while(compare and swap(s.flag,0,1)==1); // important !
        s.count++;
        if(s.count<=0){
            /*把进程P从队列移除*/
            /*把进程P插入就绪队列*/
        }
        s.flag=0; // important !
    }
    
    • PV操作: P操作用于semWait V操作用于semSignal

    • 进程按照什么顺序从队列中移除?FIFO最公平,被堵塞最久的进程最先从队列释放,采用这一策略的信号量是强信号量,没有规定队列移出顺序的信号量为弱信号量。强信号量确保了不会饥饿。

    • 二元信号量与互斥锁(mutex)的区别:为互斥量加锁的进程和解锁的进程必须为同一进程,而二元信号量可以由一个进程加锁,而另一个进程解锁

    • 信号量本质上处理的是进程进入和移出 阻塞和就绪队列

    • 信号量一般初始化为1,这样第一个执行semWait(s)的进程可以立即进入临界区,并把s的值置为0,接下来任何试图进入临界区的其他进程都会被堵塞。

      程序也可以公平的处理一次允许多个进程进入临界区的需求,这个需求可以把信号量初始化为某个特定的值来实现。无论何时s.count的值可以解释如下

      (count大于1的值的情形例子如哲学家就餐问题,虽然count大于1不能保证临界区互斥,但是没有告诉我们不能再临界区中再加一个信号量来保证互斥,外层count大于1的信号量用于限制临界区进程数量,第二个count等于1的内层信号量用于保证互斥)

      • s.count>=0:s.count是可以执行semWait(s)而不被堵塞的进程数。这种情形允许信号量支持同步和互斥。
      • s.count<0: s.count的大小是堵塞在s.queue队列中的进程数

    管程

    使用信号量设计程序是困难的,难点在于semWait和semSignal操作可能分布在整个程序中,而且很难看出信号量在这些操作上产生的整体效果。

    管程是一种结构,可以用管程来锁定对象。

    管程是由一个或多个过程(函数、方法)、一个初始化序列和局部数据组成的软件模块。(更加面向对象),管程特点如下

    • 局部数据变量只能被管程的过程访问
    • 只能调用管程的一个过程来进入管程
    • 在任何时间,只能有一个进程在管程中执行,调用管程的任何其他进程都被堵塞,

    进程不仅能够在管程中被堵塞,也能够释放这个管程,当条件满足且管程再次可用时,需要恢复该进程并允许它在堵塞点重新进入管程。

    管程使用条件变量来支持同步,cwait(c),csignal(c),如果管程中的一个进程发信号,但是没有在这个条件变量c上等待的任务,那么丢弃这个信号

    管程优于信号量的地方在于,所有的同步机制都被限制在管程内部,因此不但易于验证同步的正确性,而且易于检测出错误????

    • 使用信号的管程 ??? 未

    • 使用通知广播的管程 ??? 未

    消息传递

    xx 未

    和socket的关系???

  • 相关阅读:
    hdu 4027 Can you answer these queries?
    hdu 4041 Eliminate Witches!
    hdu 4036 Rolling Hongshu
    pku 2828 Buy Tickets
    hdu 4016 Magic Bitwise And Operation
    pku2886 Who Gets the Most Candies?(线段树+反素数打表)
    hdu 4039 The Social Network
    hdu 4023 Game
    苹果官方指南:Cocoa框架(2)(非原创)
    cocos2d 中 CCNode and CCAction
  • 原文地址:https://www.cnblogs.com/cheaptalk/p/12549665.html
Copyright © 2011-2022 走看看