GCD源碼解析
dispatch_once_t
typedef long dispatch_once_t 渠脉√笨穑可知dispatch_once_t本質是一個long類型矩桂。
void dispatch_once(dispatch_once *val,void (^block)(void)){ struct Block_basic *bb = (void *)(block); dispatch_once_f(val,block,(void *)bb->Block_invoke) }
下面我們來看保障實例唯一的核心方法dispatch_once_f
void dispatch_once_f(dispatch_once_t *val, void *ctxt, void (*func)(void *)){
volatile long *vval = val;
if (dispatch_atomic_cmpxchg(val, 0l, 1l)) {
func(ctxt); // block真正執(zhí)行
dispatch_atomic_barrier();
*val = ~0l;
}
else
{
do
{
_dispatch_hardware_pause();
} while (*vval != ~0l);
dispatch_atomic_barrier();
}
}
- dispatch_atomic_cmpxchg 本質是調用的__sync_bool_compare_and_swap((p), (o), (n))软族。一種原子操作機制,原理是如果p==0,則直接將p設置為n,返回true。否則不做任何處理财喳,返回false察迟。CSA方法。通過對CPU的操作保證原子性
- 多線程的環(huán)境下,某個線程A首次進入dispatch_once_f ,*val == 0 耳高,這個時候會將val的值設置為1,其他的線程進入的話扎瓶,會等待block的執(zhí)行完畢懂从。將val設置為~0L(0xffffffff)仪糖。
- dispatch_atomic_barrier(); 為了讓block執(zhí)行完畢再執(zhí)行更新數值的操作硼被。
- 再次進入的時候由于val變量指向內存的值已經更改為~0L.則直接會執(zhí)行else退出膀捷。