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真正执行
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的操作保证原子性
- 多线程的环境下,某个线程A首次进入dispatch_once_f ,*val == 0 ,这个时候会将val的值设置为1,其他的线程进入的话,会等待block的执行完毕。将val设置为~0L(0xffffffff)。
- dispatch_atomic_barrier(); 为了让block执行完毕再执行更新数值的操作。
- 再次进入的时候由于val变量指向内存的值已经更改为~0L.则直接会执行else退出。