GCD裡的全域性佇列
先說一下我們要用到的東西。
dispatch_queue_s裡有個屬性叫dq_serialnum。意義如名:序號。。。
overcommit:帶有 overcommit 的佇列表示每當有任務提交時,系統都會新開一個執行緒處理,這樣就不會造成某個執行緒過載(overcommit)。
原始碼裡一共定義了15個。
DISPATCH_CACHELINE_ALIGN
struct dispatch_queue_s _dispatch_main_q = {
DISPATCH_GLOBAL_OBJECT_HEADER(queue_main),
#if !DISPATCH_USE_RESOLVERS
.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_CACHELINE_ALIGN
struct dispatch_queue_s _dispatch_mgr_q = {
DISPATCH_GLOBAL_OBJECT_HEADER(queue_mgr),
.dq_state = DISPATCH_QUEUE_STATE_INIT_VALUE(1) |
DISPATCH_QUEUE_ROLE_BASE_ANON,
.do_targetq = &_dispatch_mgr_root_queue,
.dq_label = "com.apple.libdispatch-manager",
.dq_atomic_flags = DQF_WIDTH(1),
.dq_priority = DISPATCH_PRIORITY_FLAG_MANAGER |
DISPATCH_PRIORITY_SATURATED_OVERRIDE,
.dq_serialnum = 2,
};
static struct dispatch_queue_s _dispatch_mgr_root_queue = {
DISPATCH_GLOBAL_OBJECT_HEADER(queue_root),
.dq_state = DISPATCH_ROOT_QUEUE_STATE_INIT_VALUE,
.do_ctxt = &_dispatch_mgr_root_queue_context,
.dq_label = "com.apple.root.libdispatch-manager",
.dq_atomic_flags = DQF_WIDTH(DISPATCH_QUEUE_WIDTH_POOL),
.dq_priority = DISPATCH_PRIORITY_FLAG_MANAGER |
DISPATCH_PRIORITY_SATURATED_OVERRIDE,
.dq_serialnum = 3,
};
DISPATCH_CACHELINE_ALIGN
struct dispatch_queue_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_root), \
.dq_state = DISPATCH_ROOT_QUEUE_STATE_INIT_VALUE, \
.do_ctxt = &_dispatch_root_queue_contexts[ \
_DISPATCH_ROOT_QUEUE_IDX(n, flags)], \
.dq_atomic_flags = DQF_WIDTH(DISPATCH_QUEUE_WIDTH_POOL), \
.dq_priority = _dispatch_priority_make(DISPATCH_QOS_##n, 0) | flags | \
DISPATCH_PRIORITY_FLAG_ROOTQUEUE | \
((flags & DISPATCH_PRIORITY_FLAG_DEFAULTQUEUE) ? 0 : \
DISPATCH_QOS_##n << DISPATCH_PRIORITY_OVERRIDE_SHIFT), \
__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_DEFAULTQUEUE,
.dq_label = "com.apple.root.default-qos",
.dq_serialnum = 10,
),
_DISPATCH_ROOT_QUEUE_ENTRY(DEFAULT,
DISPATCH_PRIORITY_FLAG_DEFAULTQUEUE | 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,
),
};
這些全域性佇列都是由系統建立的。我們只需要dispatch_get_global_queue呼叫就可以了。先說第一個引數。
//表是轉的。如果有什麼問題。求輕罵。
系統的命名很人性化。是根據OS_ENUM給的命名。
__QOS_ENUM(qos_class, unsigned int,
QOS_CLASS_USER_INTERACTIVE
__QOS_CLASS_AVAILABLE(macos(10.10), ios(8.0)) = 0x21,
QOS_CLASS_USER_INITIATED
__QOS_CLASS_AVAILABLE(macos(10.10), ios(8.0)) = 0x19,
QOS_CLASS_DEFAULT
__QOS_CLASS_AVAILABLE(macos(10.10), ios(8.0)) = 0x15,
QOS_CLASS_UTILITY
__QOS_CLASS_AVAILABLE(macos(10.10), ios(8.0)) = 0x11,
QOS_CLASS_BACKGROUND
__QOS_CLASS_AVAILABLE(macos(10.10), ios(8.0)) = 0x09,
QOS_CLASS_UNSPECIFIED
__QOS_CLASS_AVAILABLE(macos(10.10), ios(8.0)) = 0x00,
);
1號為主佇列。2.3為管理佇列。2號的do_targetq為3號。剩下的和列舉值對應。
對應的列舉。
QOS_CLASS_USER_INTERACTIVE:要求此類工作相對於系統上的其他工作以高優先順序執行。指定這個QOS類是在幾乎所有可用系統CPU和I/O頻寬處於爭用狀態下執行的請求。這不是用於大型任務的節能QOS類。這個QOS類的使用應該僅限於與使用者的關鍵互動,例如在主事件迴圈中處理事件、檢視繪製、動畫等。我們可以看出主執行緒對應的是QOS_CLASS_USER_INTERACTIVE。
QOS_CLASS_USER_INITIATED:這類工作的優先順序要求低於關鍵的使用者互動工作,但相對高於系統上的其他工作。這不是用於大型任務的節能QOS類。它的使用應該限制在足夠短的持續時間內,這樣使用者在等待結果時就不太可能切換任務。典型的使用者發起的工作將通過顯示佔位符內容或模態使用者介面來指示進度。dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)獲取的就是QOS_CLASS_USER_INITIATED的。
QOS_CLASS_DEFAULT:這類工作的優先順序要求低於關鍵使用者互動和使用者發起的工作,但相對高於實用程式和後臺任務。pthread_create()建立的執行緒如果沒有指定QOS類的屬性,則預設為QOS_CLASS_DEFAULT。qos_class是可以設定pthread優先順序的。此QOS類值不打算用作工作分類,僅在傳播或恢復系統提供的QOS類值時設定。我們用的比較多。
QOS_CLASS_UTILITY:這類工作的優先順序要求低於關鍵使用者互動和使用者發起的工作,但相對高於低階系統維護任務。使用這個QOS類表明工作應該以一種能量和熱效率的方式執行。效用工作的進展可能會或不會向使用者顯示,但這種工作的效果是使用者可見的。對應的是我們常用的DISPATCH_QUEUE_PRIORITY_LOW。
QOS_CLASS_BACKGROUND:要求這些工作優先於其他工作執行。使用這個QOS類表明工作應該以最節能和最高效的方式執行。
4.5號我不能在app專案裡使用到。希望有知道的大佬告訴我。
我們一般獲取全域性佇列都用方法dispatch_get_global_queue。兩個引數。第一個引數是優先順序的。和上面對應。所以qos_class和DISPATCH_QUEUE_PRIORITY_HIGH都可以使用。第二個引數是用來控制是否overcommit.
上原始碼:
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;
}
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)
{
if (unlikely(qos == DISPATCH_QOS_UNSPECIFIED || qos > DISPATCH_QOS_MAX)) {
DISPATCH_CLIENT_CRASH(qos, "Corrupted priority");
}
return &_dispatch_root_queues[2 * (qos - 1) + overcommit];
}
這裡可以看到一個判斷
#define HAVE_PTHREAD_WORKQUEUE_QOS 1
#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;
}
可以為我們解決一點上面的疑問。//我很好奇他這個寫法。求教為什麼這麼寫
在這裡flags & DISPATCH_QUEUE_OVERCOMMIT作為一個bool傳給_dispatch_get_root_queue。
enum {
DISPATCH_QUEUE_OVERCOMMIT = 0x2ull,
};
這個ull就是unsigned long long。所以我們給傳一個2的話。就可以拿到有OVERCOMMIT的佇列。
最後我的測試程式碼
NSLog(@"high%@", dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0));
NSLog(@"OVERCOMMIT%@", dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0));
NSLog(@"DEFAULT%@", dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
NSLog(@"LOW%@", dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0));
NSLog(@"INITIATED%@", dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 2));
NSLog(@"BACKGROUND%@", dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 2));
NSLog(@"DEFAULT%@", dispatch_get_global_queue(QOS_CLASS_DEFAULT, 2));
NSLog(@"UTILITY%@", dispatch_get_global_queue(QOS_CLASS_UTILITY, 2));
NSLog(@"%@", dispatch_get_main_queue());
相關文章
- 07-主佇列和全域性佇列佇列
- GCD 併發佇列GC佇列
- GCD之佇列的實現和使用GC佇列
- 任務與佇列 iOS之多執行緒GCD(一)佇列iOS執行緒GC
- ios-UI高階 GCD佇列組合成圖片iOSUIGC佇列
- iOS 多執行緒--GCD 序列佇列、併發佇列以及同步執行、非同步執行iOS執行緒GC佇列非同步
- C語言裡全域性變數管理C語言變數
- 佇列順序性引發的思考佇列
- flutter 裡面的全域性變數(給web開發者)Flutter變數Web
- 線性結構 佇列與棧佇列
- 佇列、阻塞佇列佇列
- 陣列模擬佇列 以及佇列的複用(環形佇列)陣列佇列
- 如何保證訊息佇列的順序性?佇列
- 佇列-單端佇列佇列
- 2、全域性變數和列舉常量 (轉)變數
- c/c++線性迴圈佇列C++佇列
- C語言 簡單的佇列(陣列佇列)C語言佇列陣列
- 阻塞佇列一——java中的阻塞佇列佇列Java
- synchronized 中的同步佇列與等待佇列synchronized佇列
- Asp.net core mvc裡面怎麼新增全域性的FilterASP.NETMVCFilter
- 佇列 和 迴圈佇列佇列
- 【佇列】【懶排序】佇列Q佇列排序
- node 全域性物件和全域性變數物件變數
- 佇列的一種實現:迴圈佇列佇列
- laravel的佇列Laravel佇列
- 深度理解GCD執行緒死鎖,佇列,同步和非同步,序列和併發GC執行緒佇列非同步
- 微信小程式的全域性彈窗以及全域性例項微信小程式
- 佇列 手算到機算 入門 佇列 迴圈佇列佇列
- 全域性CSS的配置CSS
- 圖解--佇列、併發佇列圖解佇列
- 單調佇列雙端佇列佇列
- 佇列的順序儲存--迴圈佇列的建立佇列
- 【資料結構】佇列(順序佇列、鏈佇列)的JAVA程式碼實現資料結構佇列Java
- Python佇列的三種佇列實現方法Python佇列
- 如何保證訊息佇列的可靠性傳輸?佇列
- 資料結構:特殊的線性表之 棧 & 佇列資料結構佇列
- KMQ:基於Apache Kafka的可靠性訊息佇列MQApacheKafka佇列
- 佇列佇列