GCD基础整理

一、GCD的概念:

GCD(Grand Central Dispatch),是有Apple公司开发的一个多核编程的解决方案,用以优化应用程序支持多核处理器,是基于线程模式之上执行并发任务。

二、GCD的优点:

  1. 利用设备多核进行并行运算
  2. GCD自动充分使用设备的CPU内核
  3. GCD自动管理线程的生命周期(线程创建、线程调度、线程销毁)
  4. 使用简单

三、GCD中的任务和队列

1.任务就是需要GCD处理的操作,即需要多线程处理的代码。

任务的执行分两种:同步执行异步执行

同步执行:只能在当前线程中执行,不具备开启新线程能力,顺序等待、有序执行

异步执行:具备开启新线程能力,并发执行,不需要等待任务执行结束才能继续其他操作

2.队列就是存放被执行任务的等待队列,是一种特殊的线形表,采用先进先出的原则

队列分两类:串行队列并发队列,两者主要区别是执行顺序不同及是否有开启新线程能力

  1. 串行队列:每次只会调度一个任务,知道上个任务处理完成才会开始调度处理下一个任 务
  2. 并发队列:同时调度分发多个任务出去同时执

3.GCD使用步骤:

  1. 创建一个任务队列(串行队列、并发队列)
  2. 将任务添加到创建的等待队列并指定任务的执行类型(异步、同步)

4.队列的创建、获取方法:

  1. 串行和并行队列

    /*
    *	@param label 队列的唯一标识符,用于 DEBUG,可为空。队列的名称推荐使用应用程序 ID 这种逆序全程域名
    *	@param attr设置为串行队列还是并发队列
    */
    //dispatch_queue_create(const char *_Nullable label,dispatch_queue_attr_t _Nullable attr);
    // 串行队列的创建方法
    dispatch_queue_t queue1 = dispatch_queue_create("q1", DISPATCH_QUEUE_SERIAL);
    // 并发队列的创建方法
    dispatch_queue_t queue2 = dispatch_queue_create("q2", DISPATCH_QUEUE_CONCURRENT);
    复制代码
  2. 主队列(Main Dispatch Queue)

    所有主队列的任务会安排至主线程执行

    dispatch_queue_t q = dispatch_get_main_queue();
    复制代码
  3. 全局并发队列(Global Dispatch Queue)

    /*
    *	@param identifier 队列优先级级别(默认:DISPATCH_QUEUE_PRIORITY_DEFAULT)
    * @param flags      队列标识(默认:0)
    */
    //dispatch_get_global_queue(intptr_t identifier, uintptr_t flags);
    
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    复制代码

    注意:全局队列异步操作会新建多个线程、操作无序执行

5.任务创建方法:

// 同步执行任务创建方法
dispatch_sync(queue, ^{// 这里放同步执行任务代码});
// 异步执行任务创建方法
dispatch_async(queue, ^{// 这里放异步执行任务代码});
复制代码
    dispatch_queue_t queue1 = dispatch_queue_create("q1", DISPATCH_QUEUE_SERIAL);
    dispatch_sync(queue1, ^{
	//操作不会新建线程、操作顺序执行
        NSLog(@"同步串行%@",[NSThread currentThread]);
    });
    dispatch_async(queue1, ^{
	//操作需要一个子线程,会新建线程、线程的创建和回收不需要程序员参与,操作顺序执行,“最安全的选择”
        NSLog(@"异步串行%@",[NSThread currentThread]);
    });
    dispatch_queue_t queue2 = dispatch_queue_create("q2", DISPATCH_QUEUE_CONCURRENT);
    dispatch_sync(queue2, ^{
	//操作不会新建线程、操作顺序执行
        NSLog(@"同步并行%@",[NSThread currentThread]);
    });
    dispatch_async(queue2, ^{
	//操作会新建多个线程(有多少任务,就开n个线程执行)、操作无序执行;
	//队列前如果有其他任务,会等待前面的任务完成之后再执行;
	//场景:既不影响主线程,又不需要顺序执行的操作!
        NSLog(@"异步并行%@",[NSThread currentThread]);
    });
复制代码

注意

『主线程』 中调用 『主队列』+『同步执行』 会导致死锁问题。这是因为 主队列中追加的同步任务 和 主线程本身的任务 两者之间相互等待,阻塞了 『主队列』,最终造成了主队列所在的线程(主线程)死锁问题。而如果我们在 『其他线程』 调用 『主队列』+『同步执行』,则不会阻塞 『主队列』,自然也不会造成死锁问题。最终的结果是:不会开启新线程,串行执行任务。

6.信号量(Semaphore)

通过信号量来控制线程同步执行,wait函数使信号量减1,signal使信号量加1,当信号量小于0时会阻塞当前线程。还可以通过信号量控制线程的并发量

    // 创建并发队列
    dispatch_queue_t concurrentQueue = dispatch_queue_create("q1", DISPATCH_QUEUE_CONCURRENT);   
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    dispatch_async(concurrentQueue, ^{
        sleep(2);
        NSLog(@"async1...%@",[NSThread currentThread]);
        **dispatch_semaphore_signal(semaphore);**
    });
    
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    
    dispatch_async(concurrentQueue, ^{
        sleep(2);
        NSLog(@"async2...%@",[NSThread currentThread]);
        **dispatch_semaphore_signal(semaphore);**
    });
    
    **dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);**
    
    dispatch_async(concurrentQueue, ^{
        sleep(2);
        NSLog(@"async3...%@",[NSThread currentThread]);
    });
复制代码

7.栅栏(Barrier)

GCD中的栅栏函数作用就是总是让队列中栅栏任务之前的任务先执行,然后执行栅栏任务,接着再执行栅栏之后的任务,以此来达到多线程同步。栅栏函数的功能类似于pthread_rwlock_wrlock读/写锁。

注意:1.栅栏函数有同步栅栏(dispatch_barrier_sync)和异步栅栏(dispatch_barrier_async),区别在于同步栅栏函数会阻塞当前线程,类似于dispatch_sync,异步栅栏不会阻塞当前线程。2.创建并发队列应该使用dispatch_queue_create函数手动创建的并发队列,如果传递给此函数的队列是串行队列全局并发队列,则此函数的行为与dispatch_async函数类似。

dispatch_queue_t concurrentQueue = dispatch_queue_create("q1", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(concurrentQueue, ^{
        sleep(2);
        NSLog(@"async1...%@",[NSThread currentThread]);
    });
    dispatch_async(concurrentQueue, ^{
        sleep(2);
        NSLog(@"async1...%@",[NSThread currentThread]);
    });
    dispatch_barrier_async(concurrentQueue, ^{
        sleep(2);
        NSLog(@"async2...%@",[NSThread currentThread]);
    });
    dspatch_async(concurrentQueue, ^{
        sleep(2);
        NSLog(@"async3...%@",[NSThread currentThread]);
    });
    dispatch_async(concurrentQueue, ^{
        sleep(2);
        NSLog(@"async3...%@",[NSThread currentThread]);
    });
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享