『ios』dispatch_semaphore信号量的源码分析
2021-03-09 本文已影响0人
butterflyer
信号量dispatch_semaphore_t
其实我们只需要用的create wait signal就可以了。
如果你想要一起学习,那么跟着来吧。看完一定会有所收获。
// 创建信号量对象 信号量 >= 0
dispatch_semaphore_t sem = dispatch_semaphore_create(1);
// -1操作
dispatch_wait(sem, DISPATCH_TIME_FOREVER);
// +1 操作
dispatch_semaphore_signal(sem);
一个一个方法来分析吧。
首先是creat方法
dispatch_semaphore_t sem = dispatch_semaphore_create(1);
1.当value大于0的情况下才可以继续执行
2.申请一块dispatch_semaphore_s的内存
3.类似于生成了链表结构
dispatch_semaphore_t dispatch_semaphore_create(long value){
dispatch_semaphore_t dsema;
if (value < 0) {
return NULL;
}
// 申请内存
dsema = calloc(1, sizeof(struct dispatch_semaphore_s));
if (fastpath(dsema)) {
// do_vtable里面主要包含了这个 dispatch_semaphore_s 的操作函数
dsema->do_vtable = &_dispatch_semaphore_vtable;
//可以理解为链表的结尾标记
dsema->do_next = DISPATCH_OBJECT_LISTLESS;
// 引用计数
dsema->do_ref_cnt = 1;
dsema->do_xref_cnt = 1;
// 目标队列
dsema->do_targetq = dispatch_get_global_queue(0, 0);
// 信号值
dsema->dsema_value = value;
dsema->dsema_orig = value;
}
return dsema;
}
_dispatch_semaphore_vtable内部结构
const struct dispatch_semaphore_vtable_s _dispatch_semaphore_vtable = {
.do_type = DISPATCH_SEMAPHORE_TYPE,
.do_kind = "semaphore",
.do_dispose = _dispatch_semaphore_dispose,
.do_debug = _dispatch_semaphore_debug,
};
_dispatch_semaphore_dispose销毁信号量的意思
void _dispatch_semaphore_dispose(dispatch_semaphore_t dsema){
kern_return_t kr;
if (dsema->dsema_value < dsema->dsema_orig) {
DISPATCH_CLIENT_CRASH("Semaphore/group object deallocated while in use");
}
if (dsema->dsema_port) {
kr = semaphore_destroy(mach_task_self(), dsema->dsema_port);
DISPATCH_SEMAPHORE_VERIFY_KR(kr);
}
if (dsema->dsema_waiter_port) {
kr = semaphore_destroy(mach_task_self(), dsema->dsema_waiter_port);
DISPATCH_SEMAPHORE_VERIFY_KR(kr);
}
_dispatch_dispose(dsema);
}
下面是dispatch_semaphore_wait函数
1.减一操作,如果剪完小于0的话,就阻塞信号量。
long dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout){
// 如果信号量的值-1之后大于等于0,表示有资源可用
if (dispatch_atomic_dec(&dsema->dsema_value) >= 0) {
return 0;
}
return _dispatch_semaphore_wait_slow(dsema, timeout);
}
2.如果发生了阻塞。那么dispatch_time_t timeout就分为三种情况。
(1). DISPATCH_TIME_NOW 不等待立刻返回,KERN_OPERATION_TIMED_OUT超时,并将
dsema.value加1.
(2). DISPATCH_TIME_FOREVER无限等待, kr = semaphore_wait(dsema->dsema_port);
(3).计时等待,直到信号量到来,或超时
static long _dispatch_semaphore_wait_slow(dispatch_semaphore_t dsema, dispatch_time_t timeout){
mach_timespec_t _timeout;
kern_return_t kr;
uint64_t nsec;
long orig;
again:
_dispatch_semaphore_create_port(&dsema->dsema_port);
switch (timeout) {
default:
do {
// timeout() already calculates relative time left
nsec = _dispatch_timeout(timeout);
_timeout.tv_sec = (typeof(_timeout.tv_sec))(nsec / NSEC_PER_SEC);
_timeout.tv_nsec = (typeof(_timeout.tv_nsec))(nsec % NSEC_PER_SEC);
kr = slowpath(semaphore_timedwait(dsema->dsema_port, _timeout));
} while (kr == KERN_ABORTED);
if (kr != KERN_OPERATION_TIMED_OUT) {
DISPATCH_SEMAPHORE_VERIFY_KR(kr);
break;
}
// Fall through and try to undo what the fast path did to dsema->dsema_value
case DISPATCH_TIME_NOW:
while ((orig = dsema->dsema_value) < 0) {
if (dispatch_atomic_cmpxchg(&dsema->dsema_value, orig, orig + 1)) {
return KERN_OPERATION_TIMED_OUT;
}
}
// Another thread called semaphore_signal().
// Fall through and drain the wakeup.
case DISPATCH_TIME_FOREVER:
do {
kr = semaphore_wait(dsema->dsema_port);
} while (kr == KERN_ABORTED);
DISPATCH_SEMAPHORE_VERIFY_KR(kr);
break;
}
goto again;
}
dispatch_semaphore_signal
发送信号量,如果value>0,则说明没有阻塞,直接返回0。
DISPATCH_NOINLINE long dispatch_semaphore_signal(dispatch_semaphore_t dsema){
if (dispatch_atomic_inc(&dsema->dsema_value) > 0) {
return 0;
}
return _dispatch_semaphore_signal_slow(dsema);
}
如果小于0,_dispatch_semaphore_signal_slow函数, kr = semaphore_signal(dsema->dsema_port);发送信号量,来唤醒semaphore_wait(dsema->dsema_port)。
DISPATCH_NOINLINE static long _dispatch_semaphore_signal_slow(dispatch_semaphore_t dsema){
kern_return_t kr;
_dispatch_semaphore_create_port(&dsema->dsema_port);
// Before dsema_sent_ksignals is incremented we can rely on the reference
// held by the waiter. However, once this value is incremented the waiter
// may return between the atomic increment and the semaphore_signal(),
// therefore an explicit reference must be held in order to safely access
// dsema after the atomic increment.
_dispatch_retain(dsema);
dispatch_atomic_inc(&dsema->dsema_sent_ksignals);
// 利用系统的信号量库实现发送信号量的功能
kr = semaphore_signal(dsema->dsema_port);
DISPATCH_SEMAPHORE_VERIFY_KR(kr);
_dispatch_release(dsema);
return 1;
}
自己分析一遍绝对可以增强响应的理解,可以让自己的代码更加健壮。