0%

dispatch_once

本文使用的源码是libdispatch-1008.220.2版本。

once.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//第一部分 dispatch_once 的定义,其实是一个_dispatch_once
void
dispatch_once(dispatch_once_t *predicate,
DISPATCH_NOESCAPE dispatch_block_t block);

void
_dispatch_once(dispatch_once_t *predicate,
DISPATCH_NOESCAPE dispatch_block_t block)
{
if (DISPATCH_EXPECT(*predicate, ~0l) != ~0l) {
dispatch_once(predicate, block);
} else {
dispatch_compiler_barrier();
}
DISPATCH_COMPILER_CAN_ASSUME(*predicate == ~0l);
}
#undef dispatch_once
#define dispatch_once _dispatch_once


//第二部分 dispatch_once_f 的定义,其实是一个 ——dispatch_once_f
void
dispatch_once_f(dispatch_once_t *predicate, void *_Nullable context,
dispatch_function_t function);
void
_dispatch_once_f(dispatch_once_t *predicate, void *_Nullable context,
dispatch_function_t function)
{
if (DISPATCH_EXPECT(*predicate, ~0l) != ~0l) {
dispatch_once_f(predicate, context, function);
} else {
dispatch_compiler_barrier();
}
DISPATCH_COMPILER_CAN_ASSUME(*predicate == ~0l);
}
#undef dispatch_once_f
#define dispatch_once_f _dispatch_once_f

由上可以简单的知道,dispatch_once 调用了 dispatch_once_f方法,
为了解释DISPATCH_EXPECT,我把宏定义贴下面

1
2
3
4
5
6
7
#if __GNUC__
#define DISPATCH_EXPECT(x, v) __builtin_expect((x), (v))
#define dispatch_compiler_barrier() __asm__ __volatile__("" ::: "memory")
#else
#define DISPATCH_EXPECT(x, v) (x)
#define dispatch_compiler_barrier() do { } while (0)
#endif

头文件中用到一个DISPATCH_EXPECT宏,这个宏展开之后其实是一个GCC内置函数__builtin_expect(exp, c),在GCC手册上是这样描述这个函数的:由于大部分程序员在分支预测方面做得很糟糕,所以 GCC 提供了这个内建函数来帮助程序员处理分支预测,优化程序。其第一个参数 exp 为一个整型表达式,这个内建函数的返回值也是这个 exp ,而 c 为一个编译期常量。这个函数的语义是:你期望 exp 表达式的值等于常量 c ,从而 GCC 为你优化程序,将符合这个条件的分支放在合适的地方

我们来看实现

once.c

希望对您有所帮助,您的支持将是我莫大的动力!