底层学习03_多线程

231 阅读11分钟

多线程

关于进程和线程的概念,在本文就不过多叙述了.

开辟线程所用空间

- (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);
    }
}
  1. 新建一个线程(alloc init 一个myThread).
  2. 线程start之后会变为Runnable状态 ([thread start])
  3. CPU调度当前线程则Running, 调度其他线程时候就在Runnable(多线程)
  4. 执行完run之后, 线程就dead了
  5. 如果有sleep/等待同步锁的情况 就是blocked状态
  6. 等到同步锁了,线程变为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].