多线程之GCD探索

一、多线程理解

  1. 进程是操作系统的最小执行单元,线程是进程执行的最小单元,iOS是单进程,多线程执行的,进程之间资源不共享。
  2. 多线程可以提高程序的执行效率,其实是提高了资源的利用率,对于单核CPU来讲,通过在不同任务之间切换来达到任务同时执行的假象,对于多核CPU来讲 才是真正的并发。GCD 正是充分的利用了多核cpu

二、GCD
grand central dispatch 自动管理线程的生命周期

  1. 串行队列
dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL);
  1. 并行队列
dispatch_queue_t concurrentQueue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_CONCURRENT);
  1. 串行队列 同步执行 阻塞当前线程 不开启新线程
dispatch_sync(serialQueue  _Nonnull queue, ^{
            
 })
  1. 串行队列异步执行 不阻塞当前线程 会开辟一条新线程
dispatch_async(serialQueue  _Nonnull queue, ^{
            
})
  1. 并行队列同步执行 阻塞当前线程 不开启新线程 同 3
  2. 并行队列异步执行 不阻塞当前线程 开启新线程 ,理论上讲每dispatch_async一次都会出现一条新线程 但是系统会根据当前线程池的情况 重用以前创建过的线程。
dispatch_async(concurrentQueue, ^{
            
});
  1. 全局队列 dispatch_get_global_queue 是并行队列
  2. 主队列 dispatch_get_main_queue 是串行队列
  3. 加锁 之 信号量 dispatch_semaphore_t
  4. 栅栏函数 是阻塞队列 所以必须用在同一个队列中的 同时栅栏函数不能用全局队列 原因很简单 不能阻塞全局队列吧
dispatch_barrier_async(concurrentQueue, ^{
            
});
dispatch_semaphore_t sem = dispatch_semaphore_create(1);
for (int i = 0; i < 10; i ++){
       dispatch_async(concurrentQueue, ^{
                NSLog(@"--sem 输出-----%d",i);
                dispatch_semaphore_signal(sem);
            });
            dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
}

如果不加锁的话 0-9是乱序输出的。加上锁之后就是按照0-9的顺序输出
三、经典面试题
12. 下面代码的输出顺序

dispatch_async(concurrentQueue, ^{
            NSLog(@"1");
        });
        dispatch_async(concurrentQueue, ^{
            NSLog(@"2");
        });
        dispatch_sync(concurrentQueue, ^{
            NSLog(@"3");
        });
        NSLog(@"0");
        dispatch_async(concurrentQueue, ^{
            NSLog(@"4");
        });
        dispatch_async(concurrentQueue, ^{
            NSLog(@"5");
        });
        dispatch_sync(concurrentQueue, ^{
            NSLog(@"6");
        });

解释 输出顺序 肯定是3 在0前边 12 在3前或者3后 顺序不定。456是最后三个 顺序不定

  1. 下面代码会如何执行 死锁
dispatch_async(serialQueue, ^{
            NSLog(@"111");
            dispatch_sync(serialQueue, ^{
                NSLog(@"222");
   });
});

解释 serialQueue 是串行队列 任务是顺序执行的 此时队列中的任务是这样的 (1)NSLog(@“111”); — (2)dispatch_sync(serialQueue, ^{ }); ----(3)NSLog(@“222”); 串行队列遵循先进先出 必须要等(2)执行完才能继续执行 但是(2)执行完有必须等(3)执行完 但是(3)又得不到执行的机会 所以相互等待 死锁

四、底层分析

  1. 队列是如何创建的
    GCD的源码在libdispatch库中 通过源码一步一步调用来到
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_lane_create_with_target(const char *label, dispatch_queue_attr_t dqa,
   	dispatch_queue_t tq, bool legacy)
{
   dispatch_queue_attr_info_t dqai = _dispatch_queue_attr_to_info(dqa);
   // 开辟内存 - 生成响应的对象 queue
   dispatch_lane_t dq = _dispatch_object_alloc(vtable,
   		sizeof(struct dispatch_lane_s));
   
   if (!tq) {
   	tq = _dispatch_get_root_queue(
   			qos == DISPATCH_QOS_UNSPECIFIED ? DISPATCH_QOS_DEFAULT : qos, // 4
   			overcommit == _dispatch_queue_attr_overcommit_enabled)->_as_dq; // 0 1
   	if (unlikely(!tq)) {
   		DISPATCH_CLIENT_CRASH(qos, "Invalid queue attribute");
   	}
   }
   // 开辟内存 - 生成响应的对象 queue
   dispatch_lane_t dq = _dispatch_object_alloc(vtable,
   		sizeof(struct dispatch_lane_s));
   // 构造方法
   _dispatch_queue_init(dq, dqf, dqai.dqai_concurrent ?
   		DISPATCH_QUEUE_WIDTH_MAX : 1, DISPATCH_QUEUE_ROLE_INNER |
   		(dqai.dqai_inactive ? DISPATCH_QUEUE_INACTIVE : 0));

   // 标签
   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;// 这里的 do_targetq是通过  _dispatch_get_root_queue 获得的
   _dispatch_object_debug(dq, "%s", __func__);
   return _dispatch_trace_queue_create(dq)._dq;
}

总结:当创建队列的时候 会调用_dispatch_lane_create_with_target 然后开辟内存 初始化 设置优先级 然后从 root_queue 中获取队列 赋值给do_targetq

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值