多线程
关于进程和线程的概念,在本文就不过多叙述了.
开辟线程所用空间
- (void)viewDidLoad {
[super viewDidLoad];
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
thread.name = @"myThread";
[thread start];
NSLog(@"%lu KB", thread.stackSize / 1024);
}
- (void)run {
NSLog(@"run me");
}
2020-05-16 13:08:45.270004+0800 TheThreadStudy[9002:2417291] 512 KB
2020-05-16 13:08:45.270085+0800 TheThreadStudy[9002:2417373] run me
线程生命周期

- (void)viewDidLoad {
[super viewDidLoad];
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
thread.name = @"myThread";
[thread start];
}
- (void)run {
for (int i = 0; i < 999999; i++) {
NSLog(@"i = %d", i);
}
}
- 新建一个线程(alloc init 一个myThread).
- 线程start之后会变为Runnable状态 ([thread start])
- CPU调度当前线程则Running, 调度其他线程时候就在Runnable(多线程)
- 执行完run之后, 线程就dead了
- 如果有sleep/等待同步锁的情况 就是blocked状态
- 等到同步锁了,线程变为runnable状态,等待被CPU调度.
线程池工作原理

- 线程池大小小于核心线程池大小 可以直接开辟线程执行了
- 线程池大于核心线程池大小->线程池判断线程是否都有工作
- 存在没有工作的就交给他执行
- 都有工作的话 交给饱和策略 (4种:)
- Abort策略: 默认的 新任务提交时直接跑出未检查的异常 RejectedExecutionException,,可由调用者捕获
- CallerRuns策略: 为调节机制, 不抛弃,不放弃 不抛出异常, 将任务回退到调用者,不会再线程池的线程中执行新任务,而是在调用exector的线程中运行新任务
- Discard策略: 新提交的任务被抛弃
- DiscardOldest策略: 队列的是"队头"的任务,然后尝试提交新任务.(不适合工作队列为优先队列场景)
线程和Runloop
- (void)viewDidLoad {
[super viewDidLoad];
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
thread.name = @"myThread";
[thread start];
NSThread *thread2 = [[NSThread alloc] initWithTarget:self selector:@selector(runSecond) object:nil];
thread2.name = @"mySecondThread";
[thread2 start];
NSLog(@"thread 2 ---- %@", thread2);
for (int k = 0; k < 50; k++) {
NSThread *thread3 = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
[thread3 start];
}
}
- (void)run {
for (int i = 0; i < 9; i++) {
NSLog(@"current thread name : %@, i = %d", [NSThread currentThread], i);
}
}
- (void)runSecond {
NSLog(@"run second excuted");
[NSTimer scheduledTimerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
NSLog(@"current thread in run second : %@", [NSThread currentThread].name);
}];
}
运行结果:
2020-05-16 14:27:17.302161+0800 TheThreadStudy[9275:2464374] thread 2 ---- <NSThread: 0x600001ed13c0>{number = 7, name = mySecondThread}
2020-05-16 14:27:17.302345+0800 TheThreadStudy[9275:2464497] run second excuted
2020-05-16 14:27:17.302510+0800 TheThreadStudy[9275:2464496] current thread name : <NSThread: 0x600001ed1080>{number = 6, name = myThread}, i = 0
2020-05-16 14:27:17.302716+0800 TheThreadStudy[9275:2464498] current thread name : <NSThread: 0x600001eddb80>{number = 8, name = (null)}, i = 0
2020-05-16 14:27:17.302846+0800 TheThreadStudy[9275:2464499] current thread name : <NSThread: 0x600001edd900>{number = 9, name = (null)}, i = 0
2020-05-16 14:27:17.303264+0800 TheThreadStudy[9275:2464507] current thread name : <NSThread: 0x600001edda00>{number = 17, name = (null)}, i = 0
2020-05-16 14:27:17.312336+0800 TheThreadStudy[9275:2464547] current thread name : <NSThread: 0x600001eda580>{number = 57, name = (null)}, i = 0
2020-05-16 14:27:17.303654+0800 TheThreadStudy[9275:2464496] current thread name : <NSThread: 0x600001ed1080>{number = 6, name = myThread}, i = 1
....省略n多
解析:
- run second excuted打印了而current thread in run second没有打印.因为子线程默认是不开启runloop的.
- 后来虽然创建了很多线程,但是再没有一个线程是number=7了, 也就表示虽然runloop没开启,但是线程还是忙着的.
runloop和线程的关系:
- runloop是依赖线程存在的. 而且是1对1的.
- runloop在第一次获取时被创建,在线程结束时被销毁
- 对于主线程来说,runloop在程序启动就默认创建好了
- 对于子线程来说,runloop是懒加载的,只有当我们使用的时候才会创建,所以在子线程用定时器一定要注意:确保子线程的runloop被创建,不然定时器不会回调.
关于常驻线程在底层学习02_runloop里有写过.
GCD Grand Central Dispatch
-
将任务添加到队列,并且指定执行任务的函数
-
同步函数串行队列
- 不会开启线程,在当前线程执行任务
- 任务串行执行,任务一个接着一个
- 会产生阻塞
-
同步函数并发队列
- 不会开启线程,在当前线程执行任务
- 任务一个接着一个
-
一步函数串行队列
- 开启新线程
- 任务一个接着一个
-
异步函数并发队列
- 开启新线程, 在当前线程执行任务
- 任务异步执行,没有顺序,和cpu调度有关
-
栅栏函数
- 保证顺利执行
- 保证线程安全
- 注意点:
- 必须是自定义的队列才有效, 不能是全局并发队列. 因为系统的全局并发队列里还需要执行系统的一些别的任务, 而栅栏会堵塞.
- 依赖同一个队列,不利于封装
dispatch_queue_t concurrentQueue = dispatch_queue_create("sniper", DISPATCH_QUEUE_CONCURRENT);
/* 1.异步函数 */
dispatch_async(concurrentQueue, ^{
for (NSUInteger i = 0; i < 5; i++) {
NSLog(@"download1-%zd-%@",i,[NSThread currentThread]);
}
});
dispatch_async(concurrentQueue, ^{
for (NSUInteger i = 0; i < 5; i++) {
NSLog(@"download2-%zd-%@",i,[NSThread currentThread]);
}
});
/* 2. 栅栏函数 */
dispatch_barrier_sync(concurrentQueue, ^{
NSLog(@"---------------------%@------------------------",[NSThread currentThread]);
});
/* 3. 异步函数 */
dispatch_async(concurrentQueue, ^{
for (NSUInteger i = 0; i < 5; i++) {
NSLog(@"日常处理3-%zd-%@",i,[NSThread currentThread]);
}
});
NSLog(@"**********起来干!!");
dispatch_async(concurrentQueue, ^{
for (NSUInteger i = 0; i < 5; i++) {
NSLog(@"日常处理4-%zd-%@",i,[NSThread currentThread]);
}
});
- 调度组
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{
NSLog(@"操作0");
});
dispatch_group_async(group, queue, ^{
NSLog(@"操作1");
});
dispatch_group_notify(group, queue, ^{
NSLog(@"操作0 + 操作1 结束之后回调这里");
});
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_queue_create("com.sniper", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_enter(group);
dispatch_group_async(group, queue, ^{
NSLog(@"operation 0");
dispatch_group_leave(group);
});
dispatch_group_enter(group);
dispatch_group_async(group, queue, ^{
NSLog(@"operation 1");
dispatch_group_leave(group);
});
dispatch_group_notify(group, queue, ^{
NSLog(@"notify operation 2");
});
-
信号量 -- gcd控制并发量 锁
dispatch_queue_t queue = dispatch_get_global_queue(0, 0); // 信号量 -- gcd控制并发数 // 同步 //总结:由于设定的信号值为2,先执行2个线程,等执行完一个,才会继续执行下一个,保证同一时间执行的线程数不超过2 dispatch_semaphore_t semaphore = dispatch_semaphore_create(2); //任务1 dispatch_async(queue, ^{ dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); NSLog(@"执行任务1"); sleep(1); NSLog(@"任务1完成"); dispatch_semaphore_signal(semaphore); }); //任务2 dispatch_async(queue, ^{ dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); NSLog(@"执行任务2"); sleep(1); NSLog(@"任务2完成"); dispatch_semaphore_signal(semaphore); }); //任务3 dispatch_async(queue, ^{ dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); NSLog(@"执行任务3"); sleep(1); NSLog(@"任务3完成"); dispatch_semaphore_signal(semaphore); }); -
dispatch_source
- 可以做timer
dispatch_source_create
dispatch_source_set_event_handler
dispatch_source__merge_data
dispatch_source_get_data
dispatch_source_resume
dispatch_source_suspend
GCD源码
- 队列是如何产生的
dispatch_queue_create("com.sniper.cn", NULL)
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_NOINLINE
static dispatch_queue_t
_dispatch_lane_create_with_target(const char *label, dispatch_queue_attr_t dqa,
dispatch_queue_t tq, bool legacy)
{
// dqa 在外传进来是NULL dqai是空字典{}
dispatch_queue_attr_info_t dqai = _dispatch_queue_attr_to_info(dqa);
//
// Step 1: Normalize arguments (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;
// 区分串行还是并发
// OS_dispatch_##name##_class
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;
}
}
// 开辟空间并初始化出一个queue对象,可以理解为alloc + init
dispatch_lane_t dq = _dispatch_object_alloc(vtable,
sizeof(struct dispatch_lane_s));
// 如果是并发 queue的宽度为max 否则queue的宽度是1(也就是串行)
_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属性
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_queue_attr_info_t
_dispatch_queue_attr_to_info(dispatch_queue_attr_t dqa)
{
dispatch_queue_attr_info_t dqai = { };
// 一般我们传NULL 所以直接在这里返回了 表示串行
if (!dqa) return dqai;
// dqa有值 表示并发
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类型
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;
// 创建队列最后 return的方法:
DISPATCH_ALWAYS_INLINE
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);
}
dispatch_queue_class_t
_dispatch_introspection_queue_create(dispatch_queue_t dq)
{
dispatch_queue_introspection_context_t dqic;
size_t sz = sizeof(struct dispatch_queue_introspection_context_s);
if (!_dispatch_introspection.debug_queue_inversions) {
sz = offsetof(struct dispatch_queue_introspection_context_s,
__dqic_no_queue_inversion);
}
dqic = _dispatch_calloc(1, sz);
dqic->dqic_queue._dq = dq;
if (_dispatch_introspection.debug_queue_inversions) {
LIST_INIT(&dqic->dqic_order_top_head);
LIST_INIT(&dqic->dqic_order_bottom_head);
}
dq->do_finalizer = dqic;
_dispatch_unfair_lock_lock(&_dispatch_introspection.queues_lock);
LIST_INSERT_HEAD(&_dispatch_introspection.queues, dqic, dqic_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 upcast(dq)._dqu;
}
DISPATCH_NOINLINE
static void
_dispatch_introspection_queue_create_hook(dispatch_queue_t dq)
{
dispatch_introspection_queue_s diq;
diq = dispatch_introspection_queue_get_info(dq);
dispatch_introspection_hook_callout_queue_create(&diq);
}
DISPATCH_USED inline
dispatch_introspection_queue_s
dispatch_introspection_queue_get_info(dispatch_queue_t dq)
{
if (dx_metatype(dq) == _DISPATCH_WORKLOOP_TYPE) {
return _dispatch_introspection_workloop_get_info(upcast(dq)._dwl);
}
return _dispatch_introspection_lane_get_info(upcast(dq)._dl);
}
以上两个方法武林走哪个 最后的对象都会是dispatch_introspection_queue_s 对象
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;
}
解析:
1. 首先 根据第二个参数创建一个结构体dqai 串行就是{}, 并发的话会有一些值.
2. 给dqai的各个内容赋值(label决定queue的名字, dqa决定并发还是串行)
3. 根据dqai结构体, 创建出一个dispatch_lane_t对象. 该对象包括label,priority等等...
4.把dispatch_lane_t对象包装成dispatch_queue_t对象(中间有dispatch_introspection_queue_s, dispatch_queue_class_t, 可能还有别的)
-
除了自定义queue以外还有一些其他queue比如:
dispatch_get_main_queue(); dispatch_get_global_queue(0, 0);其实全局并发队列是从系统默认的静态数组里取的, 可以打印queue的信息,看会下queue的target
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,
),
};
```
另外我们自定义的并发队列的width是0xffe, 全局并发队列的width是0xfff.
-
dispatch_get_main_queue可以认为是串行队列的子类
// 宏定义 #define DISPATCH_DECL_SUBCLASS(name, base) OS_OBJECT_DECL_SUBCLASS(name, base) // 宏使用 DISPATCH_DECL_SUBCLASS(dispatch_queue_main, dispatch_queue_serial); -
dispatch_sync
DISPATCH_NOINLINE
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_NOINLINE
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_ALWAYS_INLINE
static inline void
_dispatch_sync_f_inline(dispatch_queue_t dq, void *ctxt,
dispatch_function_t func, uintptr_t dc_flags)
{
// width == 1 串行
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)));
}
DISPATCH_NOINLINE
static void
_dispatch_barrier_sync_f(dispatch_queue_t dq, void *ctxt,
dispatch_function_t func, uintptr_t dc_flags)
{
_dispatch_barrier_sync_f_inline(dq, ctxt, func, dc_flags);
}
DISPATCH_ALWAYS_INLINE
static inline void
_dispatch_barrier_sync_f_inline(dispatch_queue_t dq, void *ctxt,
dispatch_function_t func, uintptr_t dc_flags)
{
// 获取线程
dispatch_tid tid = _dispatch_tid_self();
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;
// The more correct thing to do would be to merge the qos of the thread
// that just acquired the barrier lock into the queue state.
//
// However this is too expensive for the fast path, so skip doing it.
// The chosen tradeoff is that if an enqueue on a lower priority thread
// contends with this fast path, this thread may receive a useless override.
//
// 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_acquire_barrier_sync(dl, tid))) {
// 内部判断的死锁
// 在__DISPATCH_WAIT_FOR_QUEUE__中 太深了就不一一贴代码了.直接到最里边的代码:
// return ((lock_value ^ tid) & DLOCK_OWNER_MASK) == 0;
// 也就是 _dispatch_lock_owner(lock_value) == tid. 注意: ^是异或操作 异或操作之后得0 表示相等.
return _dispatch_sync_f_slow(dl, ctxt, func, DC_FLAG_BARRIER, dl,
DC_FLAG_BARRIER | dc_flags);
}
if (unlikely(dl->do_targetq->do_targetq)) {
return _dispatch_sync_recurse(dl, ctxt, func,
DC_FLAG_BARRIER | dc_flags);
}
_dispatch_introspection_sync_begin(dl);
// 回调 func是外边传进来的block
// 上边的_dispatch_sync_f_slow里是invoke_and_complete_recurse递归往外调, 但是无论是invoke_and_complete 还是invoke_and_complete_recurse,
// 最后都执行_dispatch_sync_function_invoke_inline里的_dispatch_client_callout(ctxt, func);
_dispatch_lane_barrier_sync_invoke_and_complete(dl, ctxt, func
DISPATCH_TRACE_ARG(_dispatch_trace_item_sync_push_pop(
dq, ctxt, func, dc_flags | DC_FLAG_BARRIER)));
}
- dispatch_async 异步
#ifdef __BLOCKS__
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;
// 这两步 太深太复杂,总结一下所做的事
// 1. 创建线程(包括判断线程池和核心线程池的比较, 线程池是否已满等等.. )
// pthread_create创建线程
// 保存一份work赋值给dc->func
qos = _dispatch_continuation_init(dc, dq, work, 0, dc_flags);
// 执行保存过得那个dc->func
_dispatch_continuation_async(dq, dc, qos, dc->dc_flags);
}
#endif
NSOperation
- 简单使用:
// 类似target形式的operation
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(handleInvocation:) object:@"123"];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:op];
// block形式的
NSBlockOperation *bo = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@",[NSThread currentThread]);
sleep(3);
}];
//1.1 添加执行代码块
[bo addExecutionBlock:^{
NSLog(@"这是一个执行代码块 - %@",[NSThread currentThread]);
}];
//1.2 设置监听
bo.completionBlock = ^{
NSLog(@"完成了!!!");
};
//2:创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//3:添加到队列
[queue addOperation:bo];
NSLog(@"事务添加进了NSOperationQueue");
// 优先级
NSBlockOperation *bo1 = [NSBlockOperation blockOperationWithBlock:^{
for (int i = 0; i < 10; i++) {
NSLog(@"**第一个操作** %d --- %@", i, [NSThread currentThread]);
}
}];
// 设置优先级 - 最高
bo1.qualityOfService = NSQualityOfServiceUserInteractive;
//创建第二个操作
NSBlockOperation *bo2 = [NSBlockOperation blockOperationWithBlock:^{
for (int i = 0; i < 10; i++) {
NSLog(@"第二个操作 %d --- %@", i, [NSThread currentThread]);
}
}];
// 设置优先级 - 最低
bo2.qualityOfService = NSQualityOfServiceBackground;
//2:创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//3:添加到队列
[queue addOperation:bo1];
[queue addOperation:bo2];
// 线程通讯
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.name = @"Sniper";
[queue addOperationWithBlock:^{
NSLog(@"%@ = %@",[NSOperationQueue currentQueue],[NSThread currentThread]);
//模拟请求网络
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
NSLog(@"%@ --%@",[NSOperationQueue currentQueue],[NSThread currentThread]);
}];
}];
// 设置最大并发数
queue.maxConcurrentOperationCount = 2;
NSBlockOperation *bo1 = [NSBlockOperation blockOperationWithBlock:^{
[NSThread sleepForTimeInterval:0.5];
NSLog(@"请求token");
}];
NSBlockOperation *bo2 = [NSBlockOperation blockOperationWithBlock:^{
[NSThread sleepForTimeInterval:0.5];
NSLog(@"拿着token,请求数据1");
}];
NSBlockOperation *bo3 = [NSBlockOperation blockOperationWithBlock:^{
[NSThread sleepForTimeInterval:0.5];
NSLog(@"拿着数据1,请求数据2");
}];
// 建立依赖
[bo2 addDependency:bo1];
[bo3 addDependency:bo2];
// [bo1 addDependency:bo3];
[self.queue addOperations:@[bo1,bo2,bo3] waitUntilFinished:YES];
- 相对与GCD, 可操作性强
// 挂起
queue.suspended = YES; // NO
// 取消操作
[queue cancelAllOperations];
注意点
- 不要对主线程操作exit. 如果退出主线程,我们app就卡死了,因为主线程卡死了,runloop没办法处理事件,timer等
[thread exit].