To prepare

Libdispatch source

Main queue analysis

Dispatch_get_main_queue (), the main queue will be created before the main function. In the figure below, break under main and find that the main queue already exists

Open thelibdispatchSource code project, search for dispatch_get_main_queue,

dispatch_get_main_queue(void)
{
return DISPATCH_GLOBAL_OBJECT(dispatch_queue_main_t, _dispatch_main_q);
}
Copy the code
  • DISPATCH_GLOBAL_OBJECTA macro is actually passed a type and an object argument. You can think of it as passing in these two parameters to encapsulate a queue

Dispatch_queue_main_t: indicates the type. Dispatch_main_q: indicates the queue object.

  • Global search_dispatch_main_q =.

It’s actually a structure, and it inheritsDISPATCH_GLOBAL_OBJECT_HEADER, similar toobjc_classinheritanceobjc_object

Serial queues and parallel queues

We create the queue by using the dispatch_queue_create method. Look at the source code: _dispatch_lane_create_with_target is called, with more than 100 lines of code, and focus on the return value of the function.

dispatch_lane_t dq = _dispatch_object_alloc(vtable,sizeof(struct dispatch_lane_s));
_dispatch_queue_init(dq, dqf, dqai.dqai_concurrent ?
DISPATCH_QUEUE_WIDTH_MAX : 1, DISPATCH_QUEUE_ROLE_INNER |
(dqai.dqai_inactive ? DISPATCH_QUEUE_INACTIVE : 0));
Copy the code
  • _dispatch_object_alloc: Open up memory space, call_os_object_alloc_realized:
_os_object_alloc_realized(支那const* * * *void** *cls, size_t size)

{

_os_object_t obj;

dispatch_assert(size >= **sizeof**(**struct** _os_object_s));

while(unlikely(! (obj = calloc(1u, size)))) { _dispatch_temporary_resource_shortage(); } obj->os_obj_isa = cls;return* obj;

}
Copy the code

Calloc is called to open up space while OBj’s ISA points to vtable

  • _dispatch_queue_init: This is the most important to do the initialization of the queue, let after passingDQF_WIDTH(width)To distinguish between a serial queue and a concurrent queue. width =DISPATCH_QUEUE_WIDTH_MAXSo this macro, which means that’s not true, width = 1, which means serial queue.

Where dQAI: dispatch_queue_attr_info_t, in fact, is the priority of the object oriented packaging.

GCD Underlying source inheritance chain

Whatever the queue is, we will accept it as dispatch_queue_t. Follow dispatch_queue_t to see the source code:

throughDISPATCH_DECL#define DISPATCH_DECL(name) \

typedef struct name##_s : public dispatch_object_s {} *name##_t

I’m going to put dispatch_queue in there, where the ## is the link symbol, which will be removed at compile time.

  • typedef struct dispatch_queue_s : public dispatch_object_s {} *dispatch_queue_t

So there’s this inheritance link dispatch_queue_t->dispatch_queue_s->dispatch_object_s.

  • In fact, deep understandingdispatch_object_sThe bottom layer will inheritdispatch_object_t.dispatch_object_tThe bottom layer is actually a union:

GCD Task invocation process

Synchronization task

dispatch_sync(dispatch_get_global_queue(0.0), ^{
    NSLog(@"123")});Copy the code

Synchronous function block is called when, below we through the source analysis

Just through one line of thought, according toworkParameter, you can find out when the block is finally called, which is the execution of the task.

dispatch_sync->_dispatch_sync_f->_dispatch_sync_f_inline

_dispatch_sync_f_inlineWe can create new projects and try them one by one by using symbolic breakpoints. If dq_width is 1, it means serial queue, so it does not go. Under the_dispatch_sync_f_slowSymbol breakpoint to enter this method.

Continue symbol tracking_dispatch_sync_function_invoke

Found that call_dispatch_client_callout, which is the call to the block. At the same time, through the stack, we can also confirm our analysis:

Asynchronous tasks

Dispatch_async source code:

First of all by_dispatch_continuation_initEncapsulate queues and blocks. It is then passed in as a parameter_dispatch_continuation_asyncMethods.

And then search globallydx_pushmethods

Vtable is essentially a class that is encapsulated in a queue and then searcheddq_push, and discover different queues through different methods

Let’s continue tracing by starting with a global concurrent queue:_dispatch_root_queue_pushTo call_dispatch_root_queue_push_inline

Follow up: _dispatch_root_queue_push_inline->_dispatch_root_queue_poke_slow This is going to have a single column, _dispatch_root_queues_init_once, initialized

  • Thread pool initialization:_dispatch_root_queue_init_pthread_pool
  • Work queue configuration:pthread_workqueue_config
  • Execute function Settings: cfg.workq_cb =_dispatch_worker_thread2

This is also confirmed by BT printing: