GCD ⑤ Dispatch Semaphore

2022-04-13  本文已影响0人  _涼城

dispatch_semaphore_t (信号量)

    Dispatch Semaphore是持有计数的信号,该计数是多线程编程中的计数类型信号。所谓信号,类似于过马路时常用的手旗。可以通过时举起手旗,不可通过时放下手旗。而在 Dispatch Semaphore 中,使用计数来实现该功能。计数为 1 时等待,计数为1或大于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 操作。

上一篇下一篇

猜你喜欢

热点阅读