内容简介:以下仅是对Dispatch Queue的分析。GCD队列是按照层级关系来组织的:GCD中的队列Dispatch Queue是通过链表和结构体实现的。
以下仅是对Dispatch Queue的分析。
GCD队列是按照层级关系来组织的:
GCD中的几种主要的数据结构:
GCD中的队列Dispatch Queue是通过链表和结构体实现的。
队列的继承关系:
GCD中常用的结构体和宏
// 声明一个结构体,可以看出gcd内部name_t和name_s之间的关系:name_s是一个指向结构体name_t的指针。一个东西 #define DISPATCH_DECL(name) typedef struct name##_s *name##_t 复制代码
// dispatch_object_t可以是联合内部任何一种结构(仅保留Queue相关的) typedef union { struct _os_object_s *_os_obj;// 基类 struct dispatch_object_s *_do;// 基类继承os_object struct dispatch_continuation_s *_dc;// 任务结构 struct dispatch_queue_s *_dq;// 队列结构 struct dispatch_queue_attr_s *_dqa;// 队列相关属性 struct dispatch_group_s *_dg;// group结构 struct dispatch_semaphore_s *_dsema;// 信号量 } dispatch_object_t DISPATCH_TRANSPARENT_UNION; 复制代码
// 系统对象结构或者说系统基类 typedef struct _os_object_s { _OS_OBJECT_HEADER( const _os_object_vtable_s *os_obj_isa, os_obj_ref_cnt, os_obj_xref_cnt); } _os_object_s; // 系统对象头部定义宏 #define _OS_OBJECT_HEADER(isa, ref_cnt, xref_cnt) isa; // isa指针 int volatile ref_cnt; // gcd对象内部引用计数 int volatile xref_cnt // gcd对象外部引用计数(内外部都要减到0时,对象会被释放) 复制代码
struct dispatch_object_s { _DISPATCH_OBJECT_HEADER(object); }; #define _DISPATCH_OBJECT_HEADER(x) struct _os_object_s _as_os_obj[0]; //继承自os_object OS_OBJECT_STRUCT_HEADER(dispatch_##x); struct dispatch_##x##_s *volatile do_next; //链表的next struct dispatch_queue_s *do_targetq; void *do_ctxt; void *do_finalizer 复制代码
// GCD中的任务是先被封装成dispatch_continuation,再提交到队列中的。该dispatch_continuation用于存储任务所在的dispatch_group和一些其他信息,相当于一般常说的执行上下文。 typedef struct dispatch_continuation_s { struct dispatch_object_s _as_do[0];//继承自dispatch_object DISPATCH_CONTINUATION_HEADER(continuation);//continuation的一些属性 } *dispatch_continuation_t; #define DISPATCH_CONTINUATION_HEADER(x) union { const void *do_vtable; uintptr_t dc_flags; }; union { pthread_priority_t dc_priority; int dc_cache_cnt; uintptr_t dc_pad; }; struct voucher_s *dc_voucher; struct dispatch_##x##_s *volatile do_next; dispatch_function_t dc_func; // 任务函数(block会转为function) void *dc_ctxt; // 执行环境:函数参数 void *dc_data; void *dc_other 复制代码
// 队列结构体 struct dispatch_queue_s { _DISPATCH_QUEUE_HEADER(queue); DISPATCH_QUEUE_CACHELINE_PADDING; // for static queues only } DISPATCH_ATOMIC64_ALIGN; #define _DISPATCH_QUEUE_HEADER(x) struct os_mpsc_queue_s _as_oq[0]; DISPATCH_OBJECT_HEADER(x); //继承父类的属性 uint32_t dq_side_suspend_cnt; DISPATCH_UNION_LE(uint32_t volatile dq_atomic_flags, const uint16_t dq_width, //宽度:串行1,并行>1 const uint16_t __dq_opaque ); DISPATCH_INTROSPECTION_QUEUE_HEADER #define DISPATCH_INTROSPECTION_QUEUE_HEADER TAILQ_ENTRY(dispatch_queue_s) diq_list; dispatch_unfair_lock_s diq_order_top_head_lock; dispatch_unfair_lock_s diq_order_bottom_head_lock; TAILQ_HEAD(, dispatch_queue_order_entry_s) diq_order_top_head; // 队列链表头结点 TAILQ_HEAD(, dispatch_queue_order_entry_s) diq_order_bottom_head // 尾节点 // 队列属性 struct dispatch_queue_attr_s { OS_OBJECT_STRUCT_HEADER(dispatch_queue_attr); }; 复制代码
typedef struct dispatch_continuation_vtable_s { _OS_OBJECT_CLASS_HEADER(); DISPATCH_INVOKABLE_VTABLE_HEADER(dispatch_continuation); } const *dispatch_continuation_vtable_t; #define DISPATCH_INVOKABLE_VTABLE_HEADER(x) \ unsigned long const do_type; // 类型 const char *const do_kind; // 种类描述 void (*const do_invoke)(struct x##_s *, dispatch_invoke_context_t, \ dispatch_invoke_flags_t); // 执行函数 void (*const do_push)(struct x##_s *, dispatch_object_t, \ dispatch_qos_t)// 推入队列函数 串行队列实例: DISPATCH_VTABLE_SUBCLASS_INSTANCE(queue_serial, queue, .do_type = DISPATCH_QUEUE_SERIAL_TYPE, .do_kind = "serial-queue", .do_dispose = _dispatch_queue_dispose, .do_suspend = _dispatch_queue_suspend, .do_resume = _dispatch_queue_resume, .do_finalize_activation = _dispatch_queue_finalize_activation, .do_push = _dispatch_queue_push, .do_invoke = _dispatch_queue_invoke, .do_wakeup = _dispatch_queue_wakeup, .do_debug = dispatch_queue_debug, .do_set_targetq = _dispatch_queue_set_target_queue, ); 复制代码
GCD中的几种主要API:
FIFO队列的管理是通过dispatch_async等函数来实现的(操作头尾节点)。 在GCD中,可执行的任务有两种方式实现:Block、Function。因此和任务相关的API一般是有两种形式的:
dispatch_async(dispatch_queue_t queue, dispatch_block_t block); dispatch_async_f(dispatch_queue_t queue, void *_Nullable context, dispatch_function_t work); 复制代码
获取全局队列
- 实现代码
dispatch_queue_t dispatch_get_global_queue(long priority, unsigned long flags) { // 造成空值返回的原因 if (flags & ~(unsigned long)DISPATCH_QUEUE_OVERCOMMIT) { return DISPATCH_BAD_INPUT; } // 转化优先级 dispatch_qos_t qos = _dispatch_qos_from_queue_priority(priority); #if !HAVE_PTHREAD_WORKQUEUE_QOS if (qos == QOS_CLASS_MAINTENANCE) { qos = DISPATCH_QOS_BACKGROUND; } else if (qos == QOS_CLASS_USER_INTERACTIVE) { qos = DISPATCH_QOS_USER_INITIATED; } #endif if (qos == DISPATCH_QOS_UNSPECIFIED) { return DISPATCH_BAD_INPUT; } // flags传0时: overcommit = NO // 从系统队列数组中获取对应优先级的数组 return _dispatch_get_root_queue(qos, flags & DISPATCH_QUEUE_OVERCOMMIT); } 复制代码
static inline dispatch_queue_t _dispatch_get_root_queue(dispatch_qos_t qos, bool overcommit) { // _dispatch_root_queues是系统中存储不同级别队列的数组,返回数组中指定index的队列,overcommit=0/1 return &_dispatch_root_queues[2 * (qos - 1) + overcommit]; } // 数组中的队列 struct dispatch_queue_s _dispatch_root_queues[]; // skip zero // 1 - main_q 主队列 // 2 - mgr_q gcd内部管理队列 // 3 - mgr_root_q // 4,5,6,7,8,9,10,11,12,13,14,15 - global queues // 之后是手动创建的队列 复制代码
dispatch_qos_t: #define DISPATCH_QOS_UNSPECIFIED ((dispatch_qos_t)0) #define DISPATCH_QOS_MAINTENANCE ((dispatch_qos_t)1) #define DISPATCH_QOS_BACKGROUND ((dispatch_qos_t)2) #define DISPATCH_QOS_UTILITY ((dispatch_qos_t)3) #define DISPATCH_QOS_DEFAULT ((dispatch_qos_t)4) #define DISPATCH_QOS_USER_INITIATED ((dispatch_qos_t)5) #define DISPATCH_QOS_USER_INTERACTIVE ((dispatch_qos_t)6) 系统中队列的优先级枚举: enum { DISPATCH_ROOT_QUEUE_IDX_MAINTENANCE_QOS = 0, DISPATCH_ROOT_QUEUE_IDX_MAINTENANCE_QOS_OVERCOMMIT, DISPATCH_ROOT_QUEUE_IDX_BACKGROUND_QOS, DISPATCH_ROOT_QUEUE_IDX_BACKGROUND_QOS_OVERCOMMIT, DISPATCH_ROOT_QUEUE_IDX_UTILITY_QOS, DISPATCH_ROOT_QUEUE_IDX_UTILITY_QOS_OVERCOMMIT, DISPATCH_ROOT_QUEUE_IDX_DEFAULT_QOS, DISPATCH_ROOT_QUEUE_IDX_DEFAULT_QOS_OVERCOMMIT, DISPATCH_ROOT_QUEUE_IDX_USER_INITIATED_QOS, DISPATCH_ROOT_QUEUE_IDX_USER_INITIATED_QOS_OVERCOMMIT, DISPATCH_ROOT_QUEUE_IDX_USER_INTERACTIVE_QOS, DISPATCH_ROOT_QUEUE_IDX_USER_INTERACTIVE_QOS_OVERCOMMIT, _DISPATCH_ROOT_QUEUE_IDX_COUNT, }; 复制代码
- 全局队列的优先级有8中 除了正常的4种外,还有overcommit的四种
/*! * @enum 队列的一个标志位 * * @constant DISPATCH_QUEUE_OVERCOMMIT * 表示当线程池中线程用完(eg:64个线程),不管系统多么繁忙,不会等待,这个队列都会强制创建一个新的线程来执行任务。也就是说可以创建超过内核数目的线程。 */ enum { DISPATCH_QUEUE_OVERCOMMIT = 0x2ull, }; 复制代码
- 代码测试:overcommit = YES overcommit = NO
主队列
- 实现代码:
struct dispatch_queue_s _dispatch_main_q = { DISPATCH_GLOBAL_OBJECT_HEADER(queue_main), #if !DISPATCH_USE_RESOLVERS // 主队列的目标队列是:默认优先级,overcommit的globalQueue .do_targetq = &_dispatch_root_queues[ DISPATCH_ROOT_QUEUE_IDX_DEFAULT_QOS_OVERCOMMIT], #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_CANNOT_TRYSYNC | DQF_WIDTH(1), .dq_serialnum = 1, }; 复制代码
创建队列
- 代码实现
dispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr) { return _dispatch_queue_create_with_target(label, attr, DISPATCH_TARGET_QUEUE_DEFAULT(NULL), true); } static dispatch_queue_t _dispatch_queue_create_with_target(const char *label, dispatch_queue_attr_t dqa, dispatch_queue_t tq, bool legacy) { // // Step 1: Normalize arguments (qos, overcommit, tq) // dispatch_qos_t qos = _dispatch_priority_qos(dqa->dqa_qos_and_relpri); _dispatch_queue_attr_overcommit_t overcommit = dqa->dqa_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 && !tq->do_targetq && tq->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT) { // 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) { dispatch_qos_t tq_qos = _dispatch_priority_qos(tq->dq_priority); tq = _dispatch_get_root_queue(tq_qos, overcommit == _dispatch_queue_attr_overcommit_enabled); } else { 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) { // overcommit = dqa->dqa_concurrent ? _dispatch_queue_attr_overcommit_disabled : _dispatch_queue_attr_overcommit_enabled; } } if (!tq) { // 手动创建队列,未设置目标队列,则从系统队列中获取一个队列(默认优先级的globalQueue)作为目标队列,如果创建的是串行队列,则目标队列是overcommit,否则不是(:point_up_2:) tq = _dispatch_get_root_queue( qos == DISPATCH_QOS_UNSPECIFIED ? DISPATCH_QOS_DEFAULT : qos, overcommit == _dispatch_queue_attr_overcommit_enabled); } // // Step 2: Initialize the queue // if (legacy) { // if any of these attributes is specified, use non legacy classes if (dqa->dqa_inactive || dqa->dqa_autorelease_frequency) { legacy = false; } } const void *vtable; dispatch_queue_flags_t dqf = 0; if (legacy) { vtable = DISPATCH_VTABLE(queue); } else if (dqa->dqa_concurrent) { vtable = DISPATCH_VTABLE(queue_concurrent); } else { vtable = DISPATCH_VTABLE(queue_serial); } switch (dqa->dqa_autorelease_frequency) { case DISPATCH_AUTORELEASE_FREQUENCY_NEVER: dqf |= DQF_AUTORELEASE_NEVER; break; case DISPATCH_AUTORELEASE_FREQUENCY_WORK_ITEM: dqf |= DQF_AUTORELEASE_ALWAYS; break; } if (legacy) { dqf |= DQF_LEGACY; } if (label) { const char *tmp = _dispatch_strdup_if_mutable(label); if (tmp != label) { dqf |= DQF_LABEL_NEEDS_FREE; label = tmp; } } // 创建队列对象 // 分配空间 isa指向它的类型 相关属性赋值 dispatch_queue_t dq = _dispatch_object_alloc(vtable, sizeof(struct dispatch_queue_s) - DISPATCH_QUEUE_CACHELINE_PAD); // 初始化队列相关参数 _dispatch_queue_init(dq, dqf, dqa->dqa_concurrent ? DISPATCH_QUEUE_WIDTH_MAX : 1, DISPATCH_QUEUE_ROLE_INNER | (dqa->dqa_inactive ? DISPATCH_QUEUE_INACTIVE : 0)); dq->dq_label = label; dq->dq_priority = dqa->dqa_qos_and_relpri; if (!dq->dq_priority) { // 未设置优先级的队列,优先级默认继承自它的目标队列 _dispatch_queue_priority_inherit_from_target(dq, tq); } else if (overcommit == _dispatch_queue_attr_overcommit_enabled) { dq->dq_priority |= DISPATCH_PRIORITY_FLAG_OVERCOMMIT; } if (!dqa->dqa_inactive) { _dispatch_queue_inherit_wlh_from_target(dq, tq); } _dispatch_retain(tq); // 设置目标队列 dq->do_targetq = tq; _dispatch_object_debug(dq, "%s", __func__); return _dispatch_introspection_queue_create(dq); } // 构建队列内部头尾节点等 dispatch_queue_t _dispatch_introspection_queue_create(dispatch_queue_t dq) { TAILQ_INIT(&dq->diq_order_top_head);// 创建队列的头尾节点 TAILQ_INIT(&dq->diq_order_bottom_head); _dispatch_unfair_lock_lock(&_dispatch_introspection.queues_lock);// 加锁 TAILQ_INSERT_TAIL(&_dispatch_introspection.queues, dq, diq_list);// 将队列插入到队列数组中 _dispatch_unfair_lock_unlock(&_dispatch_introspection.queues_lock);// 解锁 DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK_CALLOUT(queue_create, dq); if (DISPATCH_INTROSPECTION_HOOK_ENABLED(queue_create)) { _dispatch_introspection_queue_create_hook(dq); } return dq; } 复制代码
设置目标队列
- 实现代码:
void _dispatch_queue_set_target_queue(dispatch_queue_t dq, dispatch_queue_t tq) { // global/main queue dispatch_assert(dq->do_ref_cnt != DISPATCH_OBJECT_GLOBAL_REFCNT && dq->do_targetq); // tq为空时,设置默认的目标队列同createQ if (unlikely(!tq)) { bool is_concurrent_q = (dq->dq_width > 1); tq = _dispatch_get_root_queue(DISPATCH_QOS_DEFAULT, !is_concurrent_q); } if (_dispatch_queue_try_inactive_suspend(dq)) { _dispatch_object_set_target_queue_inline(dq, tq); return dx_vtable(dq)->do_resume(dq, false); } if (unlikely(!_dispatch_queue_is_legacy(dq))) { #if 1 if (_dispatch_queue_atomic_flags(dq) & DQF_TARGETED) { DISPATCH_CLIENT_CRASH(0, "Cannot change the target of a queue " "already targeted by other dispatch objects"); } #endif DISPATCH_CLIENT_CRASH(0, "Cannot change the target of this object " "after it has been activated"); } unsigned long type = dx_type(dq); switch (type) { case DISPATCH_QUEUE_LEGACY_TYPE: #if 1 if (_dispatch_queue_atomic_flags(dq) & DQF_TARGETED) { _dispatch_bug_deprecated("Changing the target of a queue " "already targeted by other dispatch objects"); } #endif break; case DISPATCH_SOURCE_KEVENT_TYPE: case DISPATCH_MACH_CHANNEL_TYPE: _dispatch_ktrace1(DISPATCH_PERF_post_activate_retarget, dq); _dispatch_bug_deprecated("Changing the target of a source " "after it has been activated"); break; default: DISPATCH_CLIENT_CRASH(type, "Unexpected dispatch object type"); } _dispatch_retain(tq); return _dispatch_barrier_trysync_or_async_f(dq, tq, _dispatch_queue_legacy_set_target_queue, DISPATCH_BARRIER_TRYSYNC_SUSPEND); } 复制代码
向队列中同步添加任务
- 实现代码:
// 任务是block、function走的都是一样的 void dispatch_sync(dispatch_queue_t dq, dispatch_block_t work) { dispatch_sync_f(dq, work, _dispatch_Block_invoke(work)); // _dispatch_Block_invoke:block转function } 复制代码
void dispatch_sync_f(dispatch_queue_t dq, void *ctxt//函数参数, dispatch_function_t func) { // 同步任务一般不切换线程 // 如果是串行队列,则等待前面的任务执行完成才能开始执行,barrier通过信号量来实现的 if (likely(dq->dq_width == 1)) { return dispatch_barrier_sync_f(dq, ctxt, func); } // 当前队列阻塞barrier或者线程数超过了队列的容量,可能需要切换线程 if (unlikely(!_dispatch_queue_try_reserve_sync_width(dq))) { return _dispatch_sync_f_slow(dq, ctxt, func, 0); } // 如果想在当前串行队列中同步加入任务 死锁 _dispatch_introspection_sync_begin(dq); if (unlikely(dq->do_targetq->do_targetq)) { return _dispatch_sync_recurse(dq, ctxt, func, 0); } _dispatch_sync_invoke_and_complete(dq, ctxt, func);// 同步执行函数 } 复制代码
注意死锁:
向队列中异步添加任务
- 实现代码:
dispatch_async(dispatch_queue_t dq, dispatch_block_t work) { // 将任务包装成continuation 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_async_f2(dq, dc);// 中间省略了几步 } static void _dispatch_async_f2(dispatch_queue_t dq, dispatch_continuation_t dc) { if (slowpath(dq->dq_items_tail)) {// 如果当前队列中尾节点存在,说明当前队列中有任务了,就不需要再把任务在向上提交了,直接提交到当前队列中。 return dx_push(dq, dc, _dispatch_continuation_override_qos(dq, dc)); } if (slowpath(!_dispatch_queue_try_acquire_async(dq))) { return dx_push(dq, dc, _dispatch_continuation_override_qos(dq, dc)); } // 否则需要沿着链往上提交任务 return _dispatch_async_f_redirect(dq, dc, _dispatch_continuation_override_qos(dq, dc)); } // 将任务转发 _dispatch_async_f_redirect(dispatch_queue_t dq, dispatch_object_t dou, dispatch_qos_t qos) { dq = dq->do_targetq; // 根据队列的继承链,将任务一层层向上提交,直到目标队列是串行队列,其实就是将任务提交到了目标队列中了。 // #define DISPATCH_QUEUE_USES_REDIRECTION(width) \ ({ uint16_t _width = (width); \ _width > 1 && _width < DISPATCH_QUEUE_WIDTH_POOL; }) while (slowpath(DISPATCH_QUEUE_USES_REDIRECTION(dq->dq_width))) { // 省略中间内容 dq = dq->do_targetq; } dx_push(dq, dou, qos); } dx_push: static inline void _dispatch_queue_push_inline(dispatch_queue_t dq, dispatch_object_t _tail, dispatch_qos_t qos) { // 更新队列尾节点指针,插入新任务节点 struct dispatch_object_s *tail = _tail._do; dispatch_wakeup_flags_t flags = 0; bool overriding = _dispatch_queue_need_override_retain(dq, qos); if (unlikely(_dispatch_queue_push_update_tail(dq, tail))) { if (!overriding) _dispatch_retain_2(dq->_as_os_obj); _dispatch_queue_push_update_head(dq, tail); flags = DISPATCH_WAKEUP_CONSUME_2 | DISPATCH_WAKEUP_MAKE_DIRTY; } else if (overriding) { flags = DISPATCH_WAKEUP_CONSUME_2; } else { return; } return dx_wakeup(dq, qos, flags);// 唤起下个任务 } 复制代码
获取当前队列
dispatch_get_current_queue()
系统中队列是按照层级关系来组织的,获取当前队列,也就是要获取执行当前代码的线程所关联的队列,由于目标队列的这种继承关系,任务会一层层向上提交至根队列,所以dispatch_get_current_queue()获取的返回结果可能是当前执行环境中关联的队列中的任意一个与预期不同,因此使用它可能会造成错误,甚至是死锁问题。
如以下代码:由于dispatch_get_current_queue()结果的错误会执行else语句,如果当前队列就是queue,就会造成同步等待(信号量锁实现,因此也是死锁问题)
void func(dispatch_queue_t queue, dispatch_block_t block) { if (dispatch_get_current_queue() == queue) { block(); }else{ dispatch_sync(queue, block); } } 复制代码
如何实现获取当前队列:
dispatch_queue_set_specific(queue,key) // 给队列设置一个关联key
dispatch_get_specific(key) // 获取到当前任务的执行环境(一串继承链的队列)中对应key值的队列。这个就更加准确了。
dispatch_queue_t q1 = dispatch_queue_create("", NULL); dispatch_queue_t q3 = dispatch_queue_create("", NULL); dispatch_set_target_queue(q3, q1); static int specificKey; CFStringRef specificValue = CFSTR("queue1"); dispatch_queue_set_specific(q1, &specificKey, (void*)specificValue, (dispatch_function_t)CFRelease); dispatch_sync(q3, ^{ dispatch_block_t block = ^{ //do something }; // 看看关联当前这个正在执行的任务的队列链条中是否有key值是specificKey的队列即q1 CFStringRef retrievedValue = dispatch_get_specific(&specificKey); if (retrievedValue) { // 有,直接执行block block(); } else { // 没有,同步加到q1中,不会造成同步阻塞 dispatch_sync(q1, block); } }); 复制代码
实现代码:
void * dispatch_get_specific(const void *key) { if (slowpath(!key)) { return NULL; } void *ctxt = NULL; dispatch_queue_t dq = _dispatch_queue_get_current();// 获取当前任务是在哪个队列链中执行的 while (slowpath(dq)) {// 沿着链找关联key值的队列 ctxt = _dispatch_queue_get_specific_inline(dq, key); if (ctxt) break; dq = dq->do_targetq; } return ctxt; } 复制代码
GCD使用
一般当下载数据时,为了不妨碍主线程的运行,会进行异步处理。那么每次网络下载处理都要使用GCD的线程吗?答案是否定的。如果每次下载就生成一个线程,那么很可能会产生大量的线程,很快就会用尽线程池中线程和内存。因此系统提供的异步网络通信API,它生成一个线程专门用于异步下载,同时开启这个线程的runloop,添加port让runloop一直循环运行,这样线程就不会被销毁,当有下载任务时,该线程被唤醒执行任务,没任务就挂起等待。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
互联网产品运营:产品经理的10堂精英课
丁华、聂嵘海、王晶 / 电子工业出版社 / 2017-5 / 59
《互联网产品运营:产品经理的10堂精英课》共有10章,前9章分别从互联网产品运营的9个点入手,最后一章辅以案例,分析当下市场热门产品的运营模式。 第1章点明在运营产品之前需要经过缜密的策划,这样才能有明确的运营方向;第2章讲述产品运营的定位,有了准确的定位,运营才不会走偏;第3章描述用户运营,用户是一款产品的根本,没有用户,产品就是死的;第4章讲述内容运营的技巧,产品内容要怎么运营才能受到用......一起来看看 《互联网产品运营:产品经理的10堂精英课》 这本书的介绍吧!