Bottom principles of iOS - bottom principles of GCD

1. Introduction

1. What is GCD?

  • The full name is Grand Central Dispatch
  • Pure C language provides many powerful functions

2. Advantages of GCD

  • GCD is Apple's solution for multi-core parallel computing
  • GCD will automatically utilize more CPU cores (such as dual core and quad core)
  • GCD automatically manages the life cycle of a thread (create thread, schedule task, destroy thread)
  • Programmers only need to tell GCD what tasks they want to perform, and they don't need to write any thread management code

2. Tasks and queues

1. Task

  • Tasks are encapsulated with block
  • The block of the task has no parameters and no return value
1. Synchronization task
  • Function: dispatch_sync
  • You must wait for the current statement to complete before executing the next statement
  • Thread will not be opened
  • Perform block tasks at the current time
2. Asynchronous task
  • Asynchronous dispatch_async
  • You can execute the next statement without waiting for the current statement to finish executing
  • Will start the thread to execute the block task
  • Asynchrony is synonymous with multithreading

2. Queue

1. Serial queue
  • one by one;
2. Concurrent queue
  • Tasks are executed randomly without waiting, CPU scheduling
3. Main line
  • Function: dispatch_get_main_queue();
  • Special serial queue
  • Queues dedicated to scheduling tasks on the main thread
  • Thread will not be opened
  • If the current main thread is executing a task, no matter what task is currently added in the main queue, it will not be scheduled
4. Global queue
  • Function: dispatch_get_global_queue(0,0);
  • For the convenience of programmers, apple provides a global queue
  • Global queue is a concurrent queue
  • When using multithreaded development, if there is no special requirement for queues, global queues can be used directly when performing asynchronous tasks
5. Queue and task matching
  • Synchronous serial queue: do not start new thread, execute task serially;
  • Synchronous concurrent queue: do not start new thread, execute task serially;
  • Synchronous main queue: if it is called in the main thread, it will cause deadlock; if it is called in other threads, it will not open a new thread, and it will execute serially, and it will execute tasks serially in the main thread;
  • Asynchronous serial queue: start a new thread and execute tasks serially;
  • Asynchronous concurrent queue: start a new thread and execute tasks concurrently;
  • Asynchronous main queue: do not start a new thread, and execute tasks in the main thread serially
  • Deadlock:

2.GCD source code analysis

First, I made a libdispatch source code!

1. Code to create the queue

dispatch_queue_t queue = dispatch_queue_create("gcd_queue", DISPATCH_QUEUE_SERIAL);
//Here we press and hold command, Jump to Definition to jump to the following:
dispatch_queue_t
dispatch_queue_create(const char *_Nullable label,
	dispatch_queue_attr_t _Nullable attr);
//Only here
  • We can only go to libdispatch source code to see!

  • Here is the process of our source code search:

  • Search for dispatch_queue_create

  • Search_ dispatch_lane_create_with_target:

      //Finally came to the core code!!!!
      //In the following code, dqai is obtained according to the parameter dqa. The judgment of the following processes is all related to the dispatch_queue_attr_info_t dqai related
      //So, dispatch_queue_attr_t dqa is also the object we need to study
      //You can skip this code piece, first look at dqa related things, and then come back to see the following code, can make you clearer!!!!
      static dispatch_queue_t
      _dispatch_lane_create_with_target(const char *label, dispatch_queue_attr_t dqa,
      dispatch_queue_t tq, bool legacy)
      {
    
      	//Determine a temporary variable for the following code
      	dispatch_queue_attr_info_t dqai = _dispatch_queue_attr_to_info(dqa);
      	
      	//Priority DISPATCH_QOS_USER_INITIATED and DISPATCH_QOS_BACKGROUND
      	dispatch_qos_t qos = dqai.dqai_qos;
      #if !HAVE_PTHREAD_WORKQUEUE_QOS
      	if (qos == DISPATCH_QOS_USER_INTERACTIVE) {
      		dqai.dqai_qos = qos = DISPATCH_QOS_USER_INITIATED;
      	}
      	if (qos == DISPATCH_QOS_MAINTENANCE) {
      		dqai.dqai_qos = qos = DISPATCH_QOS_BACKGROUND;
      	}
      #endif // !HAVE_PTHREAD_WORKQUEUE_QOS
      	//We don't care within the asterisk
      	//***************************************************************
      	_dispatch_queue_attr_overcommit_t overcommit = dqai.dqai_overcommit;
      	if (overcommit != _dispatch_queue_attr_overcommit_unspecified && tq) {
      		if (tq->do_targetq) {
      			DISPATCH_CLIENT_CRASH(tq, "Cannot specify both overcommit and "
      			"a non-global target queue");
      		}
      	}
      	if (tq && dx_type(tq) == DISPATCH_QUEUE_GLOBAL_ROOT_TYPE) {
      		// Handle discrepancies between attr and target queue, attributes win
      		if (overcommit == _dispatch_queue_attr_overcommit_unspecified) {
      			if (tq->dq_priority & DISPATCH_PRIORITY_FLAG_OVERCOMMIT) {
      				overcommit = _dispatch_queue_attr_overcommit_enabled;
      			} else {
      				overcommit = _dispatch_queue_attr_overcommit_disabled;
      			}
      		}
      		if (qos == DISPATCH_QOS_UNSPECIFIED) {
      			qos = _dispatch_priority_qos(tq->dq_priority);
      		}
      		tq = NULL;
      	} else if (tq && !tq->do_targetq) {
      		// target is a pthread or runloop root queue, setting QoS or overcommit
      		// is disallowed
      		if (overcommit != _dispatch_queue_attr_overcommit_unspecified) {
      			DISPATCH_CLIENT_CRASH(tq, "Cannot specify an overcommit attribute "
      			"and use this kind of target queue");
      		}
      	} else {
      		if (overcommit == _dispatch_queue_attr_overcommit_unspecified) {
      			// Serial queues default to overcommit!
      			overcommit = dqai.dqai_concurrent ?
      					_dispatch_queue_attr_overcommit_disabled :
      					_dispatch_queue_attr_overcommit_enabled;
      		}
      	}
      	//***************************************************************
      	if (!tq) {
      		// The first parameter qos is 4
      		//The second parameter overcommit is 0 at the same time and 1 in the serial 
    
      		/*_dispatch_get_root_queue(dispatch_qos_t qos, bool overcommit)
      		{
      			if (unlikely(qos < DISPATCH_QOS_MIN || qos > DISPATCH_QOS_MAX)) {
      				DISPATCH_CLIENT_CRASH(qos, "Corrupted priority");
      			}
      			// 4-1= 3
      			// The return value is 2 * 3 + 0 / 1 = 6 / 7
      			return &_dispatch_root_queues[2 * (qos - 1) + overcommit];
      		}
      		_dispatch_root_queues Method definition: take the address of 6 / 7 in the following table from the array
      					
      		extern struct dispatch_queue_global_s _dispatch_root_queues[];
      		struct dispatch_queue_global_s _dispatch_root_queues[] = {
      		#define _DISPATCH_ROOT_QUEUE_IDX(n, flags) \
      				((flags & DISPATCH_PRIORITY_FLAG_OVERCOMMIT) ? \
      				DISPATCH_ROOT_QUEUE_IDX_##n##_QOS_OVERCOMMIT : \
      				DISPATCH_ROOT_QUEUE_IDX_##n##_QOS)
      		#define _DISPATCH_ROOT_QUEUE_ENTRY(n, flags, ...) \
      			[_DISPATCH_ROOT_QUEUE_IDX(n, flags)] = { \
      				DISPATCH_GLOBAL_OBJECT_HEADER(queue_global), \
      				.dq_state = DISPATCH_ROOT_QUEUE_STATE_INIT_VALUE, \
      				.do_ctxt = _dispatch_root_queue_ctxt(_DISPATCH_ROOT_QUEUE_IDX(n, flags)), \
      				.dq_atomic_flags = DQF_WIDTH(DISPATCH_QUEUE_WIDTH_POOL), \
      				.dq_priority = flags | ((flags & DISPATCH_PRIORITY_FLAG_FALLBACK) ? \
      						_dispatch_priority_make_fallback(DISPATCH_QOS_##n) : \
      						_dispatch_priority_make(DISPATCH_QOS_##n, 0)), \
      				__VA_ARGS__ \
      			}
      			_DISPATCH_ROOT_QUEUE_ENTRY(MAINTENANCE, 0,
      				.dq_label = "com.apple.root.maintenance-qos",
      				.dq_serialnum = 4,
      			),
      			_DISPATCH_ROOT_QUEUE_ENTRY(MAINTENANCE, DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
      				.dq_label = "com.apple.root.maintenance-qos.overcommit",
      				.dq_serialnum = 5,
      			),
      			_DISPATCH_ROOT_QUEUE_ENTRY(BACKGROUND, 0,
      				.dq_label = "com.apple.root.background-qos",
      				.dq_serialnum = 6,
      			),
      			_DISPATCH_ROOT_QUEUE_ENTRY(BACKGROUND, DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
      				.dq_label = "com.apple.root.background-qos.overcommit",
      				.dq_serialnum = 7,
      			),
      			_DISPATCH_ROOT_QUEUE_ENTRY(UTILITY, 0,
      				.dq_label = "com.apple.root.utility-qos",
      				.dq_serialnum = 8,
      			),
      			_DISPATCH_ROOT_QUEUE_ENTRY(UTILITY, DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
      				.dq_label = "com.apple.root.utility-qos.overcommit",
      				.dq_serialnum = 9,
      			),
      			_DISPATCH_ROOT_QUEUE_ENTRY(DEFAULT, DISPATCH_PRIORITY_FLAG_FALLBACK,
      				.dq_label = "com.apple.root.default-qos",
      				.dq_serialnum = 10,
      			),
      			_DISPATCH_ROOT_QUEUE_ENTRY(DEFAULT,
      					DISPATCH_PRIORITY_FLAG_FALLBACK | DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
      				.dq_label = "com.apple.root.default-qos.overcommit",
      				.dq_serialnum = 11,
      			),
      			_DISPATCH_ROOT_QUEUE_ENTRY(USER_INITIATED, 0,
      				.dq_label = "com.apple.root.user-initiated-qos",
      				.dq_serialnum = 12,
      			),
      			_DISPATCH_ROOT_QUEUE_ENTRY(USER_INITIATED, DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
      				.dq_label = "com.apple.root.user-initiated-qos.overcommit",
      				.dq_serialnum = 13,
      			),
      			_DISPATCH_ROOT_QUEUE_ENTRY(USER_INTERACTIVE, 0,
      				.dq_label = "com.apple.root.user-interactive-qos",
      				.dq_serialnum = 14,
      			),
      			_DISPATCH_ROOT_QUEUE_ENTRY(USER_INTERACTIVE, DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
      				.dq_label = "com.apple.root.user-interactive-qos.overcommit",
      				.dq_serialnum = 15,
      			),
      		};
      		The return value is the value of tq
      		_DISPATCH_ROOT_QUEUE_ENTRY(DEFAULT, DISPATCH_PRIORITY_FLAG_FALLBACK,
      				.dq_label = "com.apple.root.default-qos",
      				.dq_serialnum = 10,
      			),
      		_DISPATCH_ROOT_QUEUE_ENTRY(DEFAULT,
      					DISPATCH_PRIORITY_FLAG_FALLBACK | DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
      			.dq_label = "com.apple.root.default-qos.overcommit",
      			.dq_serialnum = 11,
      		),
      		*/
      		//The creation of tq template
      		tq = _dispatch_get_root_queue(
      				qos == DISPATCH_QOS_UNSPECIFIED ? DISPATCH_QOS_DEFAULT : qos, 
      				overcommit == _dispatch_queue_attr_overcommit_enabled)->_as_dq; // 0 1
      		if (unlikely(!tq)) {
      			DISPATCH_CLIENT_CRASH(qos, "Invalid queue attribute");
      		}
      	}
      	if (legacy) {
      		// if any of these attributes is specified, use non legacy classes
      		if (dqai.dqai_inactive || dqai.dqai_autorelease_frequency) {
      			legacy = false;
      		}
      	}
      	const void *vtable;
      	dispatch_queue_flags_t dqf = legacy ? DQF_MUTABLE : 0;
      	// adopt dqai.dqai_concurrent to distinguish between concurrent and serial
      	if (dqai.dqai_concurrent) {
      		//Concurrent
      		vtable = DISPATCH_VTABLE(queue_concurrent);
      	} else {
      		//serial 
      		vtable = DISPATCH_VTABLE(queue_serial);
      	}
      	switch (dqai.dqai_autorelease_frequency) {
      	case DISPATCH_AUTORELEASE_FREQUENCY_NEVER:
      		dqf |= DQF_AUTORELEASE_NEVER;
      		break;
      	case DISPATCH_AUTORELEASE_FREQUENCY_WORK_ITEM:
      		dqf |= DQF_AUTORELEASE_ALWAYS;
      		break;
      	}
      	if (label) {
      		const char *tmp = _dispatch_strdup_if_mutable(label);
      		if (tmp != label) {
      			dqf |= DQF_LABEL_NEEDS_FREE;
      			label = tmp;
      		}
      	}	
    
      	// Open memory - generate response object queue
      	dispatch_lane_t dq = _dispatch_object_alloc(vtable,
      			sizeof(struct dispatch_lane_s));
      	/*
      	Consortium:
      	typedef union {
      		struct _os_object_s *_os_obj;
      		struct dispatch_object_s *_do;
      		struct dispatch_queue_s *_dq;
      		struct dispatch_queue_attr_s *_dqa;
      		struct dispatch_group_s *_dg;
      		struct dispatch_source_s *_ds;
      		struct dispatch_mach_s *_dm;
      		struct dispatch_mach_msg_s *_dmsg;
      		struct dispatch_semaphore_s *_dsema;
      		struct dispatch_data_s *_ddata;
      		struct dispatch_io_s *_dchannel;
      	} dispatch_object_t DISPATCH_TRANSPARENT_UNION;
      	*/
    
      	//_dispatch_queue_init(dispatch_queue_class_t dqu, dispatch_queue_flags_t dqf,
      uint16_t width, uint64_t initial_state_bits)
      	// uint16_t width: dqai.dqai_concurrent ?DISPATCH_QUEUE_WIDTH_MAX : 1 
      	//If it is a concurrent queue width, it is sent to DISPATCH_QUEUE_WIDTH_MAX, serial queue width 1
      	//Several macro definitions:
      	//#define DISPATCH_QUEUE_WIDTH_FULL			0x1000ull
      	//#define DISPATCH_QUEUE_WIDTH_POOL (DISPATCH_QUEUE_WIDTH_FULL - 1) this is for queue_global use
      	//#define DISPATCH_QUEUE_WIDTH_MAX  (DISPATCH_QUEUE_WIDTH_FULL - 2) concurrent queue usage
      	// Construction method:
      	_dispatch_queue_init(dq, dqf, dqai.dqai_concurrent ?DISPATCH_QUEUE_WIDTH_MAX : 1, DISPATCH_QUEUE_ROLE_INNER | (dqai.dqai_inactive ? DISPATCH_QUEUE_INACTIVE : 0));
    
      	// label
      	dq->dq_label = label;
      	// priority
      	dq->dq_priority = _dispatch_priority_make((dispatch_qos_t)dqai.dqai_qos,
      			dqai.dqai_relpri);
      	if (overcommit == _dispatch_queue_attr_overcommit_enabled) {
      		dq->dq_priority |= DISPATCH_PRIORITY_FLAG_OVERCOMMIT;
      	}
      	if (!dqai.dqai_inactive) {
      		_dispatch_queue_priority_inherit_from_target(dq, tq);
      		_dispatch_lane_inherit_wlh_from_target(dq, tq);
      	}
      	_dispatch_retain(tq);
      	dq->do_targetq = tq;
      	_dispatch_object_debug(dq, "%s", __func__);
      	return _dispatch_trace_queue_create(dq)._dq;
      }
    
  • Search_ dispatch_queue_attr_to_info (know from above that this should be a struct type) and dispatch_queue_attr_info_t

      typedef struct dispatch_queue_attr_info_s {
      	dispatch_qos_t dqai_qos : 8;
      	int      dqai_relpri : 8;
      	uint16_t dqai_overcommit:2;
      	uint16_t dqai_autorelease_frequency:2;
      	uint16_t dqai_concurrent:1;
      	uint16_t dqai_inactive:1;
      } dispatch_queue_attr_info_t;
    
      dispatch_queue_attr_info_t
      _dispatch_queue_attr_to_info(dispatch_queue_attr_t dqa)
      {
      	//Create a new dqai structure
      	dispatch_queue_attr_info_t dqai = { };
      	//Judge whether dqa exists or not, and return directly if it does not exist,
      	//Directly return to?????
      	//What is the value of our serial queue?
      	//#define DISPATCH_QUEUE_SERIAL NULL 
      	//NULL is passed in, so a NULL structure is returned here
      	if (!dqa) return dqai;
      	//If it is not a serial queue, assign the following dqai structure
      #if DISPATCH_VARIANT_STATIC
      	if (dqa == &_dispatch_queue_attr_concurrent) {
      		dqai.dqai_concurrent = true;
      		return dqai;
      	}
      #endif
    
      	if (dqa < _dispatch_queue_attrs ||
      			dqa >= &_dispatch_queue_attrs[DISPATCH_QUEUE_ATTR_COUNT]) {
      		DISPATCH_CLIENT_CRASH(dqa->do_vtable, "Invalid queue attribute");
      	}
    
      	// Apple's algorithm
      	size_t idx = (size_t)(dqa - _dispatch_queue_attrs);
    
      	// Bitfield
      	// 0000 000000000 00000000000 0000 000  1
      	//Assignment of dqa structural body field
      	dqai.dqai_inactive = (idx % DISPATCH_QUEUE_ATTR_INACTIVE_COUNT);
      	idx /= DISPATCH_QUEUE_ATTR_INACTIVE_COUNT;
    
      	dqai.dqai_concurrent = !(idx % DISPATCH_QUEUE_ATTR_CONCURRENCY_COUNT);
      	idx /= DISPATCH_QUEUE_ATTR_CONCURRENCY_COUNT;
    
      	dqai.dqai_relpri = -(idx % DISPATCH_QUEUE_ATTR_PRIO_COUNT);
      	idx /= DISPATCH_QUEUE_ATTR_PRIO_COUNT;
    
      	dqai.dqai_qos = idx % DISPATCH_QUEUE_ATTR_QOS_COUNT;
      	idx /= DISPATCH_QUEUE_ATTR_QOS_COUNT;
    
      	dqai.dqai_autorelease_frequency =
      	idx % DISPATCH_QUEUE_ATTR_AUTORELEASE_FREQUENCY_COUNT;
      	idx /= DISPATCH_QUEUE_ATTR_AUTORELEASE_FREQUENCY_COUNT;
    
      	dqai.dqai_overcommit = idx % DISPATCH_QUEUE_ATTR_OVERCOMMIT_COUNT;
      	idx /= DISPATCH_QUEUE_ATTR_OVERCOMMIT_COUNT;
    
      	return dqai;
      }
      //After that, let's go back to the top_ dispatch_lane_create_with_target code to continue to analyze!!!!
    

2. Creation of main queue and global queue

1.dispatch_get_global_queue(0, 0)
dispatch_queue_global_t
dispatch_get_global_queue(long identifier, unsigned long flags);

typedef struct dispatch_queue_global_s *dispatch_queue_global_t;
struct dispatch_queue_global_s _dispatch_root_queues[] = {
#define _DISPATCH_ROOT_QUEUE_IDX(n, flags) \
	((flags & DISPATCH_PRIORITY_FLAG_OVERCOMMIT) ? \
	DISPATCH_ROOT_QUEUE_IDX_##n##_QOS_OVERCOMMIT : \
	DISPATCH_ROOT_QUEUE_IDX_##n##_QOS)
#define _DISPATCH_ROOT_QUEUE_ENTRY(n, flags, ...) \
	[_DISPATCH_ROOT_QUEUE_IDX(n, flags)] = { \
		DISPATCH_GLOBAL_OBJECT_HEADER(queue_global), \
		.dq_state = DISPATCH_ROOT_QUEUE_STATE_INIT_VALUE, \
		.do_ctxt = _dispatch_root_queue_ctxt(_DISPATCH_ROOT_QUEUE_IDX(n, flags)), \
		.dq_atomic_flags = DQF_WIDTH(DISPATCH_QUEUE_WIDTH_POOL), \
		.dq_priority = flags | ((flags & DISPATCH_PRIORITY_FLAG_FALLBACK) ? \
				_dispatch_priority_make_fallback(DISPATCH_QOS_##n) : \
				_dispatch_priority_make(DISPATCH_QOS_##n, 0)), \
		__VA_ARGS__ \
	}
	_DISPATCH_ROOT_QUEUE_ENTRY(MAINTENANCE, 0,
		.dq_label = "com.apple.root.maintenance-qos",
		.dq_serialnum = 4,
	),
	_DISPATCH_ROOT_QUEUE_ENTRY(MAINTENANCE, DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
		.dq_label = "com.apple.root.maintenance-qos.overcommit",
		.dq_serialnum = 5,
	),
	_DISPATCH_ROOT_QUEUE_ENTRY(BACKGROUND, 0,
		.dq_label = "com.apple.root.background-qos",
		.dq_serialnum = 6,
	),
	_DISPATCH_ROOT_QUEUE_ENTRY(BACKGROUND, DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
		.dq_label = "com.apple.root.background-qos.overcommit",
		.dq_serialnum = 7,
	),
	_DISPATCH_ROOT_QUEUE_ENTRY(UTILITY, 0,
		.dq_label = "com.apple.root.utility-qos",
		.dq_serialnum = 8,
	),
	_DISPATCH_ROOT_QUEUE_ENTRY(UTILITY, DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
		.dq_label = "com.apple.root.utility-qos.overcommit",
		.dq_serialnum = 9,
	),
	_DISPATCH_ROOT_QUEUE_ENTRY(DEFAULT, DISPATCH_PRIORITY_FLAG_FALLBACK,
		.dq_label = "com.apple.root.default-qos",
		.dq_serialnum = 10,
	),
	_DISPATCH_ROOT_QUEUE_ENTRY(DEFAULT,
		DISPATCH_PRIORITY_FLAG_FALLBACK | DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
		.dq_label = "com.apple.root.default-qos.overcommit",
		.dq_serialnum = 11,
	),
	_DISPATCH_ROOT_QUEUE_ENTRY(USER_INITIATED, 0,
		.dq_label = "com.apple.root.user-initiated-qos",
		.dq_serialnum = 12,
	),
	_DISPATCH_ROOT_QUEUE_ENTRY(USER_INITIATED, DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
		.dq_label = "com.apple.root.user-initiated-qos.overcommit",
		.dq_serialnum = 13,
	),
	_DISPATCH_ROOT_QUEUE_ENTRY(USER_INTERACTIVE, 0,
		.dq_label = "com.apple.root.user-interactive-qos",
		.dq_serialnum = 14,
	),
	_DISPATCH_ROOT_QUEUE_ENTRY(USER_INTERACTIVE, DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
		.dq_label = "com.apple.root.user-interactive-qos.overcommit",
		.dq_serialnum = 15,
	),
};
//global_ Queues are also created using templates
2.dispatch_get_main_queue()
dispatch_queue_main_t
dispatch_get_main_queue(void)
{
	return DISPATCH_GLOBAL_OBJECT(dispatch_queue_main_t, _dispatch_main_q);
}
typedef struct dispatch_queue_static_s *dispatch_queue_main_t;
struct dispatch_queue_static_s _dispatch_main_q = {
DISPATCH_GLOBAL_OBJECT_HEADER(queue_main),
#if !DISPATCH_USE_RESOLVERS
	.do_targetq = _dispatch_get_default_queue(true),
#endif
	.dq_state = DISPATCH_QUEUE_STATE_INIT_VALUE(1) |
			DISPATCH_QUEUE_ROLE_BASE_ANON,
	.dq_label = "com.apple.main-thread",
	.dq_atomic_flags = DQF_THREAD_BOUND | DQF_WIDTH(1),
	.dq_serialnum = 1, //From here we can see that the main queue is a serial queue
};
//struct dispatch_queue_static_s main queue is created using a static

3._ dispatch_ root_ Creation of queues []

  • This creation process loads the dynamic library libdispatch_ Created when dyld

      //establish
      void _dispatch_introspection_init(void)
      {
      	_dispatch_introspection.debug_queue_inversions =
      			_dispatch_getenv_bool("LIBDISPATCH_DEBUG_QUEUE_INVERSIONS", false);
    
      	// Hack to determine queue TSD offset from start of pthread structure
      	uintptr_t thread = _dispatch_thread_self();
      	thread_identifier_info_data_t tiid;
      	mach_msg_type_number_t cnt = THREAD_IDENTIFIER_INFO_COUNT;
      	kern_return_t kr = thread_info(pthread_mach_thread_np((void*)thread),
      	THREAD_IDENTIFIER_INFO, (thread_info_t)&tiid, &cnt);
      	if (!dispatch_assume_zero(kr)) {
      		_dispatch_introspection.thread_queue_offset =
      				(void*)(uintptr_t)tiid.dispatch_qaddr - (void*)thread;
      	}
      	_dispatch_thread_key_create(&dispatch_introspection_key, _dispatch_introspection_thread_remove);
      	_dispatch_introspection_thread_add(); // add main thread
      	//Loop creation_ dispatch_root_queues[i];
      	for (size_t i = 0; i < DISPATCH_ROOT_QUEUE_COUNT; i++) {
      		_dispatch_trace_queue_create(&_dispatch_root_queues[i]);
      	}
      #if DISPATCH_USE_MGR_THREAD && DISPATCH_USE_PTHREAD_ROOT_QUEUES
      	_dispatch_trace_queue_create(_dispatch_mgr_q.do_targetq);
      #endif
      	_dispatch_trace_queue_create(&_dispatch_main_q);//Main queue creation
      	_dispatch_trace_queue_create(&_dispatch_mgr_q);
      }
    
      //Create method
      static inline dispatch_queue_class_t
      _dispatch_trace_queue_create(dispatch_queue_class_t dqu)
      {
      	_dispatch_only_if_ktrace_enabled({
      		uint64_t dq_label[4] = {0}; // So that we get the right null termination
      		dispatch_queue_t dq = dqu._dq;
      		strncpy((char *)dq_label, (char *)dq->dq_label ?: "", sizeof(dq_label));
    
      		_dispatch_ktrace2(DISPATCH_QOS_TRACE_queue_creation_start,
      				dq->dq_serialnum,
      				_dispatch_priority_to_pp_prefer_fallback(dq->dq_priority));
    
      		_dispatch_ktrace4(DISPATCH_QOS_TRACE_queue_creation_end,
      				dq_label[0], dq_label[1], dq_label[2], dq_label[3]);
      	});
    
      	return _dispatch_introspection_queue_create(dqu);
      }
    
  • The main queue is created separately during initialization, and is not used_ dispatch_root_queues [] template creation! Others are created through_ dispatch_root_queues [] create

At this point, the queue creation process of GCD has been explored. It's written in a mess and analyzed carefully. Next, I'll look at the knowledge related to functions. Please look forward to

Keywords: Attribute Asterisk C

Added by anushka on Sat, 13 Jun 2020 10:46:25 +0300