美文网首页
GCD ⑤ Dispatch Semaphore

GCD ⑤ Dispatch Semaphore

作者: _涼城 | 来源:发表于2022-04-13 14:06 被阅读0次

    dispatch_semaphore_t (信号量)

        Dispatch Semaphore是持有计数的信号,该计数是多线程编程中的计数类型信号。所谓信号,类似于过马路时常用的手旗。可以通过时举起手旗,不可通过时放下手旗。而在 Dispatch Semaphore 中,使用计数来实现该功能。计数为 1 时等待,计数为1或大于1时不等待。 下面介绍一下使用方法。

    • dispatch_semaphore_create 创建信号量
    • dispatch_semaphore_wait 信号量等待 -1
    • dispatch_semaphore_signal 信号量释放 +1
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
    dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 1ull * NSEC_PER_SEC );
    long result = dispatch_semaphore_wait(semaphore, time);
    if ( result == 0 ) {
        /** 
        *由于 Dispatch Semaphore 的计数值达到大于等于1
        *或者在待机中的指定时间内
        *Dispatch Semaphore 的计数值达到大于等于1
        *所以Dispatch Semaphore 的计数值减去1。
        *可执行需要进行排他控制的处理
        */
    } else {
        /**
        *由于 Dispatch Semaphore 的计数值为0
        *因此在达到指定时间为止待机
        */
    }
    

    dispatch_semaphore_wait 函数返回 0 时,可安全地执行需要进行排他控制的处理。该处理结束时通过 dispatch_semaphore_signal 函数将 Dispatch Semaphore 的计数值加 1。

    dispatch_semaphore_create 实现

    dispatch_semaphore_t
    dispatch_semaphore_create(long value)
    {
        dispatch_semaphore_t dsema;
    
        // If the internal value is negative, then the absolute of the value is
        // equal to the number of waiting threads. Therefore it is bogus to
        // initialize the semaphore with a negative value.
        if (value < 0) {
            return DISPATCH_BAD_INPUT;
        }
        //创建对象 OS_dispatch_semaphore
        dsema = _dispatch_object_alloc(DISPATCH_VTABLE(semaphore),
                sizeof(struct dispatch_semaphore_s));
        dsema->do_next = DISPATCH_OBJECT_LISTLESS;
        dsema->do_targetq = _dispatch_get_default_queue(false);
        //赋值
        dsema->dsema_value = value;
        // 初始化一个定位在 sema 的匿名 Posix信号量
        _dispatch_sema4_init(&dsema->dsema_sema, _DSEMA4_POLICY_FIFO);
        dsema->dsema_orig = value;
        return dsema;
    }
    

        dispatch_semaphore_create 初始化信号量 dsemavalue 必须 >= 0。

    dispatch_semaphore_wait 实现

    intptr_t
    dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout)
    {
     long value = os_atomic_dec2o(dsema, dsema_value, acquire);
     if (likely(value >= 0)) {
      return 0;
     }
     return _dispatch_semaphore_wait_slow(dsema, timeout);
    }
    

        在 dispatch_semaphore_wait 调用 os_atomic_dec2o 得到 value,如果 value >= 0 则返回 0。那么 os_atomic_dec2o 是什么呢?

    os_atomic_dec2o

    #define os_atomic_dec2o(p, f, m) \
            os_atomic_sub2o(p, f, 1, m)
    
    #define os_atomic_sub2o(p, f, v, m) \
            os_atomic_sub(&(p)->f, (v), m)
    
    #define os_atomic_sub(p, v, m) \
            _os_atomic_c11_op((p), (v), m, sub, -)
    
    #define _os_atomic_c11_op(p, v, m, o, op) \
      ({ _os_atomic_basetypeof(p) _v = (v), _r = \
      atomic_fetch_##o##_explicit(_os_atomic_c11_atomic(p), _v, \
      memory_order_##m); (__typeof__(_r))(_r op _v); })
    

        通过上面源码得知 os_atomic_dec2o(dsema, dsema_value, acquire) 等同于 atomic_fetch_sub_explicit( _os_atomic_c11_atomic(dsema->dsema_value),1,memory_order_acquire)

        atomic_fetch_sub_explicit(volatile A * obj,M arg,memory_order order) 函数是对 obj 减去 arg 的值,因此,是对 dsema->dsema_value 进行 -1 操作。

    dispatch_semaphore_signal 实现

    intptr_t
    dispatch_semaphore_signal(dispatch_semaphore_t dsema)
    {
     long value = os_atomic_inc2o(dsema, dsema_value, release);
     if (likely(value > 0)) {
      return 0;
     }
     if (unlikely(value == LONG_MIN)) {
      DISPATCH_CLIENT_CRASH(value,
        "Unbalanced call to dispatch_semaphore_signal()");
     }
     return _dispatch_semaphore_signal_slow(dsema);
    }
    

    os_atomic_inc2o

    #define os_atomic_inc2o(p, f, m) \
            os_atomic_add2o(p, f, 1, m)
    
    #define os_atomic_add2o(p, f, v, m) \
            os_atomic_add(&(p)->f, (v), m)
    
    #define os_atomic_add(p, v, m) \
            _os_atomic_c11_op((p), (v), m, add, +)
    
    #define _os_atomic_c11_op(p, v, m, o, op) \
      ({ _os_atomic_basetypeof(p) _v = (v), _r = \
      atomic_fetch_##o##_explicit(_os_atomic_c11_atomic(p), _v, \
      memory_order_##m); (__typeof__(_r))(_r op _v); })
    

        同 dispatch_semaphore_wait 一样, atomic_fetch_add_explicit(volatile A * obj,M arg,memory_order order) 函数是对 obj 加上 arg 的值,因此,是对 dsema->dsema_value 进行 +1 操作。

    相关文章

      网友评论

          本文标题:GCD ⑤ Dispatch Semaphore

          本文链接:https://www.haomeiwen.com/subject/eslasrtx.html