基本概念
行程和執行緒
- 行程:行程是指在系統中正在運行的一個應用程式
- 執行緒:1個行程要想執行任務,必須得有執行緒(每1個行程至少要有1條執行緒)
- 一個行程(程式)的所有任務都在執行緒中執行
- 1個執行緒中任務的執行是串行的
行程和執行緒的比較
- 執行緒是CPU呼叫(執行任務)的最小單位
- 行程是CPU分配資源和調度的單位
- 一個程式可以對應多個行程,一個行程中可以有多個執行緒,但至少要有一個執行緒
- 同一個行程內的執行緒共享行程的資源
多執行緒
- 1個行程中可以開啟多條執行緒,每條執行緒可以并行(同時)執行不同的任務
- 同一時間,CPU只能處理1條執行緒,只有1條執行緒在作業(執行)
- 多執行緒并發(同時)執行,其實是CPU快速地在多條執行緒之間調度(切換)
- 如果CPU調度執行緒的時間足夠快,就造成了多執行緒并發執行的假象
優點
- 能適當提高程式的執行效率
- 能適當提高資源利用率(CPU、記憶體利用率)
缺點
- 創建執行緒是有開銷的
- 如果開啟大量的執行緒,會降低程式的性能
- 執行緒越多,CPU在調度執行緒上的開銷就越大
- 程式設計更加復雜:比如執行緒之間的通信、多執行緒的資料共享
主執行緒
- 一個iOS程式運行后,默認會開啟1條執行緒,稱為“主執行緒”或“UI執行緒”
- 顯示\重繪UI界面
- 處理UI事件(比如點擊事件、滾動事件、拖拽事件等)
- 別將比較耗時的操作放到主執行緒中
iOS中的常見多執行緒方案

NSThread、GCD、NSOperation底層都是基于pthread來實作的
NSThread
判斷以及獲取執行緒的方法
// 1.獲得主執行緒
NSThread *mainThread = [NSThread mainThread];
// 2.獲得當前執行緒
NSThread *currentThread = [NSThread currentThread];
// 3.判斷主執行緒
// 類方法
BOOL isMainThreadA = [NSThread isMainThread];
// 物件方法
BOOL isMainThreadB = [currentThread isMainThread];
創建執行緒的方法
// 1.手動啟動執行緒
// 可以拿到執行緒物件進行詳細設定
// object:需要傳遞的引數
NSThread *threadA = [[NSThread alloc]initWithTarget:self selector:@selector(run:) object:@"ABC"];
// 設定屬性
threadA.name = @"執行緒A";
//設定優先級 取值范圍 0.0 ~ 1.0 之間 最高是1.0 默認優先級是0.5
threadA.threadPriority = 1.0;
// 啟動執行緒
[threadA start];
// 2.自動啟動執行緒
// 無法對執行緒進行更詳細的設定
[NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"分離子執行緒"];
// 3.開啟一條后臺執行緒
[self performSelectorInBackground:@selector(run:) withObject:@"開啟后臺執行緒"];
其他常用方法
// 1.阻塞執行緒
[NSThread sleepForTimeInterval:2.0];
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:3.0]];
// 2.回到主執行緒
// waitUntilDone:是否需要等待
[self performSelectorOnMainThread:@selector(showImage:) withObject:image waitUntilDone:YES];
[self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES];
// 3.可以設定在哪個執行緒執行
[self performSelector:@selector(showImage:) onThread:[NSThread mainThread] withObject:image waitUntilDone:YES];
// 4.退出執行緒
//注意:執行緒死了不能復生
[NSThread exit];
NSOperation
NSOperation的基本使用
// 1.創建操作
// alloc init 方式創建操作
NSInvocationOperation *op1 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(download1) object:nil];
// block 方式創建操作
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"1----%@",[NSThread currentThread]);
}];
// 2.追加任務
// 注意:如果一個操作中的任務數量大于1,那么會開子執行緒并發執行任務
// 注意:不一定是子執行緒,有可能是主執行緒
[op2 addExecutionBlock:^{
NSLog(@"2---%@",[NSThread currentThread]);
}];
// 3.啟動
[op1 start];
[op2 start];
// 4.操作監聽
// 執行操作完畢后會執行該回呼
op2.completionBlock = ^{
NSLog(@"%@",[NSThread currentThread]);
};
// 5.設定依賴
// 注意點:不能回圈依賴
// 可以跨佇列依賴
[op1 addDependency:op2];
佇列的基本使用
第一種創建方式
// 1.創建操作,封裝任務
NSInvocationOperation *op1 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(download1) object:nil];
// 2.創建佇列
// 非主佇列: (同時具備并發和串行的功能)
// 默認情況下,非主佇列是并發佇列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 3.添加操作到佇列中
[queue addOperation:op1]; //內部已經呼叫了[op1 start]
第二種創建方式
// 1.創建操作
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"1----%@",[NSThread currentThread]);
}];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"2----%@",[NSThread currentThread]);
}];
// 追加任務
[op2 addExecutionBlock:^{
NSLog(@"3----%@",[NSThread currentThread]);
}];
// 2.創建佇列
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
// 3.添加操作到佇列
[queue addOperation:op1];
[queue addOperation:op2];
第三種創建方式
// 1.創建佇列
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
// 2.佇列直接添加一個操作(省略創建操作)
[queue addOperationWithBlock:^{
NSLog(@"1----%@",[NSThread currentThread]);
}];
第四種創建方式
// 1.創建佇列
// LLOperation繼承自NSOperation
LLOperation *op1 = [[LLOperation alloc]init];
// 2.LLOperation內部重寫 main 方法
- (void)main {
NSLog(@"main---%@",[NSThread currentThread]);
}
// 3.創建佇列
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
// 4.添加操作到佇列
[queue addOperation:op1];
佇列的其他用法
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
// 1.設定最大并發數量
/*
同一時間最多有多少個任務可以執行
串行執行任務!=只開一條執行緒 (執行緒同步)
maxConcurrentOperationCount >1 那么就是并發佇列
maxConcurrentOperationCount == 1 那就是串行佇列
maxConcurrentOperationCount == 0 不會執行任務
maxConcurrentOperationCount == -1 特殊意義 最大值 表示不受限制
*/
queue.maxConcurrentOperationCount = 5;
// 2.暫停(可以恢復)
// YES代表暫停佇列,NO代表恢復佇列
/*
佇列中的任務也是有狀態的:已經執行完畢的 | 正在執行 | 排隊等待狀態
不能暫停當前正在處于執行狀態的任務
*/
[queue setSuspended:YES];
// 3.取消(不可以恢復)
// 該方法內部呼叫了所有操作的cancel方法
[queue cancelAllOperations];
// 4.創建主佇列
// 會在主執行緒執行操作,不開執行緒
NSOperationQueue *queue = [NSOperationQueue mainQueue];
總結:
NSOperation是個抽象類,并不具備封裝操作的能力,必須使用它的子類- 默認情況下,
NSInvocationOperation呼叫了start方法后并不會開一條新執行緒去執行操作,而是在當前執行緒同步執行操作;
只有將NSOperation放到一個NSOperationQueue中,才會異步執行操作 - 只要
NSBlockOperation封裝的運算元> 1,就會異步執行操作 - 操作之間不能相互依賴,會造成回圈依賴
- 經常通過
- (BOOL)isCancelled方法檢測操作是否被取消,對取消做出回應
GCD
GCD的佇列
GCD的佇列可以分為2大型別
- 并發佇列(Concurrent Dispatch Queue)
- 可以讓多個任務并發(同時)執行(自動開啟多個執行緒同時執行任務)
- 并發功能只有在異步
dispatch_async函式下才有效
- 串行佇列(Serial Dispatch Queue)
- 讓任務一個接著一個地執行(一個任務執行完畢后,再執行下一個任務)
// 1.創建佇列
/*
第一個引數:C語言的字串,標簽
第二個引數:佇列的型別
DISPATCH_QUEUE_CONCURRENT:并發
DISPATCH_QUEUE_SERIAL:串行
*/
// 并發佇列
dispatch_queue_t queue = dispatch_queue_create("com.haha", DISPATCH_QUEUE_CONCURRENT);
// 串行佇列
dispatch_queue_t queue = dispatch_queue_create("com.haha", DISPATCH_QUEUE_SERIAL);
// 2.獲得全域并發佇列
// 第一個引數:可以設定優先級
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 3.獲得主佇列
dispatch_queue_t queue = dispatch_get_main_queue();
// 4.異步函式
dispatch_async(queue, ^{
NSLog(@"download1----%@",[NSThread currentThread]);
});
// 5.同步函式
dispatch_sync(queue, ^{
NSLog(@"download2----%@",[NSThread currentThread]);
});
同步、異步、并發、串行的注意點:
- 同步和異步主要影響:能不能開啟新的執行緒 - 同步:在當前執行緒中執行任務,不具備開啟新執行緒的能力 - 異步:在新的執行緒中執行任務,具備開啟新執行緒的能力- 并發和串行主要影響:任務的執行方式 - 并發:多個任務并發(同時)執行 - 串行:一個任務執行完畢后,再執行下一個任務
創建一個同步串行佇列
// 不論是哪種佇列,都不會開啟新執行緒
dispatch_queue_t queue = dispatch_queue_create("com.haha", DISPATCH_QUEUE_SERIAL);
// dispatch_queue_t queue = dispatch_queue_create("com.haha", DISPATCH_QUEUE_CONCURRENT);
// dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_sync(queue, ^{
NSLog(@"%@", [NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"%@", [NSThread currentThread]);
});
// 列印輸出:
// <NSThread: 0x6000020198c0>{number = 1, name = main}
// <NSThread: 0x6000020191c0>{number = 1, name = main}
創建一個異步并發佇列
// 并發佇列
dispatch_queue_t queue = dispatch_queue_create("com.haha", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"%@", [NSThread currentThread]);
});
// 列印輸出:
// <NSThread: 0x6000020198c0>{number = 4, name = (null)}
// <NSThread: 0x6000020191c0>{number = 5, name = (null)}
創建一個異步串行佇列
// 串行佇列
dispatch_queue_t queue = dispatch_queue_create("com.haha", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
NSLog(@"%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"%@", [NSThread currentThread]);
});
// 列印輸出:
// <NSThread: 0x6000020198c0>{number = 5, name = (null)}
// <NSThread: 0x6000020191c0>{number = 5, name = (null)}
在主佇列中,不論是同步還是異步都不會開啟子執行緒
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_async(queue, ^{
NSLog(@"%@", [NSThread currentThread]);
});
// 列印輸出:
// <NSThread: 0x6000020198c0>{number = 1, name = main}
但是使用sync函式往當前串行佇列中添加任務,會卡住當前的串行佇列(產生死鎖)
綜上所述可以用一張圖來概述

dispatch_get_global_queue和dispatch_queue_create的區別
我們在代碼里分別創建兩種佇列,然后列印發現,全域佇列的地址都是同一個,而dispatch_queue_create的物件都不相同
dispatch_queue_t queue1 = dispatch_get_global_queue(0, 0);
dispatch_queue_t queue2 = dispatch_get_global_queue(0, 0);
dispatch_queue_t queue3 = dispatch_queue_create("queu3", DISPATCH_QUEUE_CONCURRENT);
dispatch_queue_t queue4 = dispatch_queue_create("queu4", DISPATCH_QUEUE_CONCURRENT);
dispatch_queue_t queue5 = dispatch_queue_create("queu5", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"%p %p %p %p %p", queue1, queue2, queue3, queue4, queue5);
// 分別輸出:0x10c5d8080 0x10c5d8080 0x6000037c3180 0x6000037c1580 0x6000037c3200
GCD的佇列組
第一種創建方式
// 1.創建佇列
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
// 2.創建佇列組
dispatch_group_t group = dispatch_group_create();
// 3.把任務添加到佇列中
dispatch_group_async(group, queue, ^{
NSLog(@"1----%@",[NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{
NSLog(@"2----%@",[NSThread currentThread]);
});
// 4.攔截通知,當佇列組中所有的任務都執行完畢的時候回進入到下面的方法
dispatch_group_notify(group, queue, ^{
NSLog(@"-------dispatch_group_notify-------");
});
第二種創建方式
// 1.創建佇列
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
// 2.創建佇列組
dispatch_group_t group = dispatch_group_create();
// 3.在該方法后面的異步任務會被納入到佇列組的監聽范圍,進入群組
// dispatch_group_enter|dispatch_group_leave 必須要配對使用
dispatch_group_enter(group);
dispatch_async(queue, ^{
NSLog(@"1----%@",[NSThread currentThread]);
//離開群組
dispatch_group_leave(group);
});
dispatch_group_enter(group);
dispatch_async(queue, ^{
NSLog(@"2----%@",[NSThread currentThread]);
//離開群組
dispatch_group_leave(group);
});
// 攔截通知
// 內部本身是異步的
dispatch_group_notify(group, queue, ^{
NSLog(@"-------dispatch_group_notify-------");
});
第三種方式
// 1.創建佇列
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
// 2.創建佇列組
dispatch_group_t group = dispatch_group_create();
// 3.把任務添加到佇列中
dispatch_group_async(group, queue, ^{
NSLog(@"1----%@",[NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{
NSLog(@"2----%@",[NSThread currentThread]);
});
// 4.會阻塞執行緒
// 直到佇列組中所有的任務都執行完畢之后才能執行
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
NSLog(@"----end----");
其他常用方法
// 1.延遲執行的幾種方法
// 1.1
[self performSelector:@selector(task) withObject:nil afterDelay:2.0];
// 1.2
// repeats:是否重復呼叫
[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(task) userInfo:nil repeats:YES];
// 1.3
// 可以設定佇列控制在哪個執行緒執行延遲
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), queue, ^{
NSLog(@"GCD----%@",[NSThread currentThread]);
});
// 2.一次性代碼
// 整個程式運行程序中只會執行一次
// onceToken用來記錄該部分的代碼是否被執行過
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"---once----");
});
// 3.快速遍歷
// 開多個執行緒進行遍歷
/*
第一個引數:遍歷的次數
第二個引數:佇列(并發佇列)
第三個引數:index 索引
*/
dispatch_apply(10, dispatch_get_global_queue(0, 0), ^(size_t index) {
NSLog(@"%zd---%@",index,[NSThread currentThread]);
});
// 4.柵欄函式
// 柵欄函式不能使用全域并發佇列
// 柵欄函式之后的執行緒都會延后執行
dispatch_queue_t queue = dispatch_queue_create("download", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"%@", [NSThread currentThread]);
});
dispatch_barrier_async(queue, ^{
NSLog(@"+++++++++++++++++++++++++++++");
});
dispatch_async(queue, ^{
NSLog(@"%@", [NSThread currentThread]);
});
分析底層實作
原始碼下載
我們可以通過GCD的原始碼libdispatch.dylib來分析內部實作
libdispatch.dylib的下載地址:https://opensource.apple.com/release/macos-1015.html
然后找到libdispatch-1173.0.3進行下載

原始碼分析
dispatch_queue_create的底層實作
我們在queue.c檔案中搜索dispatch_queue_create,可以找到對應實作
dispatch_queue_t
dispatch_queue_create(const char *label, dispatch_queue_attr_t attr)
{
return _dispatch_lane_create_with_target(label, attr,
DISPATCH_TARGET_QUEUE_DEFAULT, true);
}
進入_dispatch_lane_create_with_target
DISPATCH_NOINLINE
static dispatch_queue_t
_dispatch_lane_create_with_target(const char *label, dispatch_queue_attr_t dqa,
dispatch_queue_t tq, bool legacy)
{
// dqai 創建
dispatch_queue_attr_info_t dqai = _dispatch_queue_attr_to_info(dqa);
//
// Step 1: Normalize arguments (qos, overcommit, tq)
// 第一步:規范化引數,例如qos, overcommit, tq
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
_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) {
tq = _dispatch_get_root_queue(
qos == DISPATCH_QOS_UNSPECIFIED ? DISPATCH_QOS_DEFAULT : qos,
overcommit == _dispatch_queue_attr_overcommit_enabled)->_as_dq;
if (unlikely(!tq)) {
DISPATCH_CLIENT_CRASH(qos, "Invalid queue attribute");
}
}
//
// Step 2: Initialize the queue
// 第二步:初始化佇列
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;
if (dqai.dqai_concurrent) {
vtable = DISPATCH_VTABLE(queue_concurrent);
} else {
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;
}
}
// 創建佇列,并初始化
dispatch_lane_t dq = _dispatch_object_alloc(vtable,
sizeof(struct dispatch_lane_s));
// 根據dqai.dqai_concurrent的值,判斷是串行還是并發佇列
_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;
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;
}
_dispatch_trace_queue_create內部會一步步呼叫_dispatch_introspection_queue_create -> _dispatch_introspection_queue_create_hook -> dispatch_introspection_queue_get_info,最終可以找到是通過_dispatch_introspection_lane_get_info通過模板來創建的佇列
DISPATCH_ALWAYS_INLINE
static inline dispatch_introspection_queue_s
_dispatch_introspection_lane_get_info(dispatch_lane_class_t dqu)
{
dispatch_lane_t dq = dqu._dl;
bool global = _dispatch_object_is_global(dq);
uint64_t dq_state = os_atomic_load2o(dq, dq_state, relaxed);
dispatch_introspection_queue_s diq = {
.queue = dq->_as_dq,
.target_queue = dq->do_targetq,
.label = dq->dq_label,
.serialnum = dq->dq_serialnum,
.width = dq->dq_width,
.suspend_count = _dq_state_suspend_cnt(dq_state) + dq->dq_side_suspend_cnt,
.enqueued = _dq_state_is_enqueued(dq_state) && !global,
.barrier = _dq_state_is_in_barrier(dq_state) && !global,
.draining = (dq->dq_items_head == (void*)~0ul) ||
(!dq->dq_items_head && dq->dq_items_tail),
.global = global,
.main = dx_type(dq) == DISPATCH_QUEUE_MAIN_TYPE,
};
return diq;
}
_dispatch_lane_create_with_target詳細步驟決議
1.呼叫_dispatch_queue_attr_to_info傳入dqa,創建dispatch_queue_attr_info_t型別的dqai,用于存盤佇列的相關屬性資訊
dispatch_queue_attr_info_t
_dispatch_queue_attr_to_info(dispatch_queue_attr_t dqa)
{
dispatch_queue_attr_info_t dqai = { };
if (!dqa) return dqai;
#if DISPATCH_VARIANT_STATIC
// 默認為serial和null
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");
}
size_t idx = (size_t)(dqa - _dispatch_queue_attrs);
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 = -(int)(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;
}
2.通過_dispatch_object_alloc創建佇列dq
void *
_dispatch_object_alloc(const void *vtable, size_t size)
{
#if OS_OBJECT_HAVE_OBJC1
const struct dispatch_object_vtable_s *_vtable = vtable;
dispatch_object_t dou;
dou._os_obj = _os_object_alloc_realized(_vtable->_os_obj_objc_isa, size);
dou._do->do_vtable = vtable;
return dou._do;
#else
return _os_object_alloc_realized(vtable, size);
#endif
}
內部呼叫_os_object_alloc_realized,可以看出佇列內部也有一個isa指標,所以佇列也是物件
inline _os_object_t
_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;
}
3.通過_dispatch_queue_init設定佇列的相關屬性
static inline dispatch_queue_class_t
_dispatch_queue_init(dispatch_queue_class_t dqu, dispatch_queue_flags_t dqf,
uint16_t width, uint64_t initial_state_bits)
{
uint64_t dq_state = DISPATCH_QUEUE_STATE_INIT_VALUE(width);
dispatch_queue_t dq = dqu._dq;
dispatch_assert((initial_state_bits & ~(DISPATCH_QUEUE_ROLE_MASK |
DISPATCH_QUEUE_INACTIVE)) == 0);
if (initial_state_bits & DISPATCH_QUEUE_INACTIVE) {
dq->do_ref_cnt += 2; // rdar://8181908 see _dispatch_lane_resume
if (dx_metatype(dq) == _DISPATCH_SOURCE_TYPE) {
dq->do_ref_cnt++; // released when DSF_DELETED is set
}
}
dq_state |= initial_state_bits;
dq->do_next = DISPATCH_OBJECT_LISTLESS;
dqf |= DQF_WIDTH(width);
os_atomic_store2o(dq, dq_atomic_flags, dqf, relaxed);
dq->dq_state = dq_state;
dq->dq_serialnum =
os_atomic_inc_orig(&_dispatch_queue_serial_numbers, relaxed);
return dqu;
}
總結:
上述分析可以通過下圖來概述

dispatch_async的底層實作
在queue.c中找到dispatch_async,其內部的實作如下
void
dispatch_async(dispatch_queue_t dq, dispatch_block_t work)
{
dispatch_continuation_t dc = _dispatch_continuation_alloc();
uintptr_t dc_flags = DC_FLAG_CONSUME;
dispatch_qos_t qos;
// 任務包裝函式
qos = _dispatch_continuation_init(dc, dq, work, 0, dc_flags);
// 并發處理函式
_dispatch_continuation_async(dq, dc, qos, dc->dc_flags);
}
1.在_dispatch_continuation_init中進行任務的封裝
DISPATCH_ALWAYS_INLINE
static inline dispatch_qos_t
_dispatch_continuation_init(dispatch_continuation_t dc,
dispatch_queue_class_t dqu, dispatch_block_t work,
dispatch_block_flags_t flags, uintptr_t dc_flags)
{
// 拷貝任務
void *ctxt = _dispatch_Block_copy(work);
dc_flags |= DC_FLAG_BLOCK | DC_FLAG_ALLOCATED;
if (unlikely(_dispatch_block_has_private_data(work))) {
dc->dc_flags = dc_flags;
dc->dc_ctxt = ctxt; // 賦值
// will initialize all fields but requires dc_flags & dc_ctxt to be set
return _dispatch_continuation_init_slow(dc, dqu, flags);
}
// 封裝任務,異步回呼
dispatch_function_t func = _dispatch_Block_invoke(work);
if (dc_flags & DC_FLAG_CONSUME) {
func = _dispatch_call_block_and_release;
}
return _dispatch_continuation_init_f(dc, dqu, ctxt, func, flags, dc_flags);
}
_dispatch_Block_invoke是一個宏,主要就是對任務的封裝
#define _dispatch_Block_invoke(bb) \
((dispatch_function_t)((struct Block_layout *)bb)->invoke)
2.在_dispatch_continuation_async中并發處理函式
DISPATCH_ALWAYS_INLINE
static inline void
_dispatch_continuation_async(dispatch_queue_class_t dqu,
dispatch_continuation_t dc, dispatch_qos_t qos, uintptr_t dc_flags)
{
#if DISPATCH_INTROSPECTION
if (!(dc_flags & DC_FLAG_NO_INTROSPECTION)) {
_dispatch_trace_item_push(dqu, dc); // 跟蹤日志
}
#else
(void)dc_flags;
#endif
return dx_push(dqu._dq, dc, qos);
}
其中的dx_push是一個宏
#define dx_push(x, y, z) dx_vtable(x)->dq_push(x, y, z)
其中的dq_push需要根據佇列的型別,執行不同的函式
總結:
上述分析可以通過下圖來概述

dispatch_sync的底層實作
在queue.c中找到dispatch_async,其內部的實作如下
void
dispatch_sync(dispatch_queue_t dq, dispatch_block_t work)
{
uintptr_t dc_flags = DC_FLAG_BLOCK;
if (unlikely(_dispatch_block_has_private_data(work))) {
return _dispatch_sync_block_with_privdata(dq, work, dc_flags);
}
_dispatch_sync_f(dq, work, _dispatch_Block_invoke(work), dc_flags);
}
然后呼叫到_dispatch_sync_f
static void
_dispatch_sync_f(dispatch_queue_t dq, void *ctxt, dispatch_function_t func,
uintptr_t dc_flags)
{
_dispatch_sync_f_inline(dq, ctxt, func, dc_flags);
}
然后呼叫到_dispatch_sync_f_inline,發現其內部是用柵欄函式實作的
static inline void
_dispatch_sync_f_inline(dispatch_queue_t dq, void *ctxt,
dispatch_function_t func, uintptr_t dc_flags)
{
if (likely(dq->dq_width == 1)) { // 表示串行佇列
return _dispatch_barrier_sync_f(dq, ctxt, func, dc_flags); // 柵欄函式
}
if (unlikely(dx_metatype(dq) != _DISPATCH_LANE_TYPE)) {
DISPATCH_CLIENT_CRASH(0, "Queue type doesn't support dispatch_sync");
}
dispatch_lane_t dl = upcast(dq)._dl;
// Global concurrent queues and queues bound to non-dispatch threads
// always fall into the slow case, see DISPATCH_ROOT_QUEUE_STATE_INIT_VALUE
if (unlikely(!_dispatch_queue_try_reserve_sync_width(dl))) {
return _dispatch_sync_f_slow(dl, ctxt, func, 0, dl, dc_flags); // 死鎖
}
if (unlikely(dq->do_targetq->do_targetq)) {
return _dispatch_sync_recurse(dl, ctxt, func, dc_flags);
}
_dispatch_introspection_sync_begin(dl); // 處理當前資訊
_dispatch_sync_invoke_and_complete(dl, ctxt, func DISPATCH_TRACE_ARG(
_dispatch_trace_item_sync_push_pop(dq, ctxt, func, dc_flags))); // block執行并釋放
}
在_dispatch_sync_f_slow中,當前的主佇列會被阻塞掛起
static void
_dispatch_sync_f_slow(dispatch_queue_class_t top_dqu, void *ctxt,
dispatch_function_t func, uintptr_t top_dc_flags,
dispatch_queue_class_t dqu, uintptr_t dc_flags)
{
dispatch_queue_t top_dq = top_dqu._dq;
dispatch_queue_t dq = dqu._dq;
if (unlikely(!dq->do_targetq)) {
return _dispatch_sync_function_invoke(dq, ctxt, func);
}
pthread_priority_t pp = _dispatch_get_priority();
struct dispatch_sync_context_s dsc = {
.dc_flags = DC_FLAG_SYNC_WAITER | dc_flags,
.dc_func = _dispatch_async_and_wait_invoke,
.dc_ctxt = &dsc,
.dc_other = top_dq,
.dc_priority = pp | _PTHREAD_PRIORITY_ENFORCE_FLAG,
.dc_voucher = _voucher_get(),
.dsc_func = func,
.dsc_ctxt = ctxt,
.dsc_waiter = _dispatch_tid_self(),
};
_dispatch_trace_item_push(top_dq, &dsc);
__DISPATCH_WAIT_FOR_QUEUE__(&dsc, dq);
if (dsc.dsc_func == NULL) {
dispatch_queue_t stop_dq = dsc.dc_other;
return _dispatch_sync_complete_recurse(top_dq, stop_dq, top_dc_flags);
}
_dispatch_introspection_sync_begin(top_dq);
_dispatch_trace_item_pop(top_dq, &dsc);
_dispatch_sync_invoke_and_complete_recurse(top_dq, ctxt, func,top_dc_flags
DISPATCH_TRACE_ARG(&dsc));
}
總結:
上述分析可以通過下圖來概述

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/274023.html
標籤:iOS
