征服iOS程序员

iOS多线程-GCD

2017-10-29  本文已影响15人  乔克蜀黍

简介

Grand Central Dispatch (GCD)是Apple开发的一个多核编程的较新的解决方法。它主要用于优化应用程序以支持多核处理器以及其他对称多处理系统。它是一个在线程池模式的基础上执行的并行任务。--摘自百度百科。

GCD是一套可以充分合理的利用CPU资源,同时可以处理比较复杂的多线程问题的多线程解决方案。

优点

使用

GCD是使用还是比较简单的,这里可以总结为一句话:队列以并行或串行的方式执行任务,所以要明白两个重要概念,队列和串行、并行。

队列

队列用来存放待执行的任务,队列按照FIFO(先进先出)执行任务,即先加入队列的任务先被执行,后加入的排队等待,执行完的任务从队列中释放。队列分为两种,串行队列和并行队列。

// 串行队列
dispatch_queue_t queue= dispatch_queue_create("SerialTest.queue", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t queue= dispatch_queue_create("SerialTest.queue", NULL);
// 并行队列
dispatch_queue_t queue= dispatch_queue_create("Concurrent Test.queue", DISPATCH_QUEUE_CONCURRENT);

同步和异步

GCD提供了这两个函数dispatch_syncdispatch_async分别表示同步执行和异步执行,同步和异步的主要区别是是否会阻塞当前线程所,调用dispatch_sync会阻塞调用该函数的线程,直到block里的任务执行完成函数才会返回,当前线程才会继续执行。dispatch_async不会阻塞当前线程,当前线程会继续往下执行。
系统会根据调用的同步或异步函数和任务加入的队列类型来决定是否需要新开线程,有如下几种组合方式:

串行队列 并行队列 主队列
同步执行 不会开新线程,串行执行 不会开新线程,串行执行 可能会线程死锁
异步执行 会开一条新线程,串行执行 会开新线程,并行执行 不会开新线程,串行执行

我们在开发中最常用的组合是异步执行并行队列,当程序要执行一些例如下载、上传数据等耗时操作时,如果不想阻塞UI线程,就可以把耗时操作交给GCD来处理。

dispatch_async(dispatch_get_global_queue(0, 0), ^{
        /*
         ......
         耗时操作
         ......
         */
        //任务完成,返回主线程刷洗UI
        dispatch_async(dispatch_get_main_queue(), ^{
            //刷新UI
        });
    });

GCD线程死锁
线程死锁指的是两个线程互相等待对方执行完成从而造成谁也无法执行,由于GCD的同步执行函数dispatch_sync会阻塞当前线程,所以经常会造成线程死锁,当使用dispatch_sync时要格外注意。

- (void)viewDidLoad {
    [super viewDidLoad];
    
    NSLog(@"任务执行前 %@",[NSThread currentThread]);
    dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"执行任务 %@",[NSThread currentThread]);
    });
    NSLog(@"执行任务后 %@",[NSThread currentThread]);
}

运行以上代码,在打印完NSLog(@"任务执行前 %@",[NSThread currentThread]);这句后,直接抛出如下异常

运行结果.png
以上异常就是由于线程死锁引起的,当程序执行到dispatch_sync函数,这个函数会把当前线程(主线程)阻塞掉,然后把任务加入到主队列中,也就是把任务交给主线程来执行,然后这时候主线程是阻塞状态,所以block里的任务不会被执行,而主线程要想执行后面的代码,必须要等待dispatch_sync函数返回,这就造成了死锁。
上一篇 下一篇

猜你喜欢

热点阅读