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
初始化信号量 dsema
,value
必须 >= 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 操作。
网友评论