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 thelibdispatch
Source 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_OBJECT
A 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_class
inheritanceobjc_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_MAX
So 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 understanding
dispatch_object_s
The bottom layer will inheritdispatch_object_t
.dispatch_object_t
The 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 towork
Parameter, 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_inline
We 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_slow
Symbol 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_init
Encapsulate queues and blocks. It is then passed in as a parameter_dispatch_continuation_async
Methods.
And then search globallydx_push
methods
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_push
To 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: