dispatch_queue
前言
dispatch_queue 按FIFO顺序串行调用提交给它们的 block。一个 queue 一次只能调用一个 block,但是独立的 queue 可以彼此并发地调用各自的 block。系统管理了一个线程池,该线程池处理调度队列并调用提交给它们的 block。调度队列通过调用dispatch_retain()
和dispatch_release()
来进行引用计数。提交到 queue 中的block,在被执行完成之前,会持有对 queue 的一个引用。一旦一个 queue 的所有引用被释放了,系统将会销毁 queue。
正文
0x0. dispatch_queue_t
声明如下:
#define DISPATCH_DECL(name) typedef struct name##_s *name##_t
DISPATCH_DECL(dispatch_queue);
1
2
2
所以 最终应是这样的:dispatch_queue_t
typedef struct dispatch_queue_s *dispatch_queue_t
0x1. dispatch_async(queue, block);
实现如下:
typedef struct dispatch_continuation_s {
struct dispatch_object_s _as_do[0];
DISPATCH_CONTINUATION_HEADER(continuation);
} *dispatch_continuation_t;
void dispatch_async(dispatch_queue_t dq, dispatch_block_t work)
{
dispatch_continuation_t dc = _dispatch_continuation_alloc();
uintptr_t dc_flags = DISPATCH_OBJ_CONSUME_BIT;
_dispatch_continuation_init(dc, dq, work, 0, 0, dc_flags);
_dispatch_continuation_async(dq, dc);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
64位下DISPATCH_CONTINUATION_HEADER
宏展开如下:
typedef struct dispatch_continuation_s {
struct dispatch_object_s _as_do[0];
union {
const void *do_vtable;
uintptr_t dc_flags;
};
union {
pthread_priority_t dc_priority;
int dc_cache_cnt;
uintptr_t dc_pad;
};
struct dispatch_continuation_s *volatile do_next;
struct voucher_s *dc_voucher;
dispatch_function_t dc_func;
void *dc_ctxt;
void *dc_data;
void *dc_other
} *dispatch_continuation_t;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
_dispatch_continuation_init
函数实现:
static inline void _dispatch_continuation_init(dispatch_continuation_t dc,
dispatch_queue_class_t dqu,
dispatch_block_t work,
pthread_priority_t pp,
dispatch_block_flags_t flags,
uintptr_t dc_flags)
{
dc->dc_flags = dc_flags | DISPATCH_OBJ_BLOCK_BIT;
dc->dc_ctxt = _dispatch_Block_copy(work);
_dispatch_continuation_priority_set(dc, pp, flags);
if (unlikely(_dispatch_block_has_private_data(work))) {
// always sets dc_func & dc_voucher
// may update dc_priority & do_vtable
return _dispatch_continuation_init_slow(dc, dqu, flags);
}
if (dc_flags & DISPATCH_OBJ_CONSUME_BIT) {
dc->dc_func = _dispatch_call_block_and_release;
} else {
dc->dc_func = _dispatch_Block_invoke(work);
}
_dispatch_continuation_voucher_set(dc, dqu, flags);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
_dispatch_block_has_private_data
函数通过判断 block 的 invoke 指针是否为_dispatch_block_special_invoke
,来表明是否有 private data. (Tip1)
#define _dispatch_Block_invoke(bb) ((dispatch_function_t)((struct Block_layout *)bb)->invoke)
// linux下与非linux下差了个下划线
extern void DISPATCH_BLOCK_SPECIAL_INVOKE(void *)
#ifdef __linux__
asm("___dispatch_block_create_block_invoke");
#else
asm("____dispatch_block_create_block_invoke");
#endif
void (*_dispatch_block_special_invoke)(void*) = DISPATCH_BLOCK_SPECIAL_INVOKE;
static inline bool _dispatch_block_has_private_data(const dispatch_block_t block)
{
extern void (*_dispatch_block_special_invoke)(void*);
return (_dispatch_Block_invoke(block) == _dispatch_block_special_invoke);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Tip1
这里的涉及到了一点汇编知识,确切地说是内联汇编,将上述代码简化下
void myFunction(NSString *name) {
NSLog(@"%@", name);
}
// 获取myFunction函数的指针,值得注意的是:变量funcptr不需要加*号,这和我们常规声明函数指针变量不同
void funcptr(NSString *) asm("_myFunction");
// 等同于上述源码中的`void (*_dispatch_block_special_invoke)(void*) = DISPATCH_BLOCK_SPECIAL_INVOKE;`
void (*ptr)(NSString *) = funcptr;
// 调用
ptr(@"我是参数");
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12