GCD源碼解析
dispatch_once_t
typedef long dispatch_once_t ??芍猟ispatch_once_t本質(zhì)是一個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 本質(zhì)是調(diào)用的__sync_bool_compare_and_swap((p), (o), (n))。一種原子操作機制,原理是如果p==0,則直接將p設(shè)置為n,返回true。否則不做任何處理,返回false。CSA方法。通過對CPU的操作保證原子性
- 多線程的環(huán)境下,某個線程A首次進入dispatch_once_f ,*val == 0 ,這個時候會將val的值設(shè)置為1,其他的線程進入的話,會等待block的執(zhí)行完畢。將val設(shè)置為~0L(0xffffffff)。
- dispatch_atomic_barrier(); 為了讓block執(zhí)行完畢再執(zhí)行更新數(shù)值的操作。
- 再次進入的時候由于val變量指向內(nèi)存的值已經(jīng)更改為~0L.則直接會執(zhí)行else退出。