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

所以 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

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

_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

_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

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
最后更新: 11/25/2019, 9:20:12 PM