多线程之GCD

GCD,Grand Central Dispatch,iOS中常用的多线程技术,GCD提供C风格的API,相对NSOperationQueue以及NSThread,它更加的简单易用且功能强大.

注意:现在dispatc_group_t,dispatch_queue_t, dispatch_semaphore_t等已经被ARC管理,无需要手动release.

队列 dispatch_queue_t

GCD提供两种队列Serial Dispatch Queue(串行队列),Concurrent Dispatch Queue(并发队列). 使用APIdispatch_queue_create创建.

 dispatch_queue_t requestHeaderModificationQueue = dispatch_queue_create("requestHeaderModificationQueue", DISPATCH_QUEUE_CONCURRENT);

第一个参数为队列的名字, 也可以写为NULL,不过为了调试推荐指定对列名字.
第二个参数为DISPATCH_QUEUE_CONCURRENTDISPATCH_QUEUE_SERIAL,用于指定队列的类型.

dispatch_async(requestHeaderModificationQueue, ^{
           .........
        });
dispatch_release(requestHeaderModificationQueue);

GCD的队列,必须由程序员手动进行引用计数的管理,当队列需要释放的时候,要手动的调用dispatch_release. 上面的代码不会立即释放队列,因为block强引用了requestHeaderModificationQueue,会等block中的任务执行完毕才会释放队列.

同时GCD提供dispatch_get_main_queue()dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)可以便捷的获取主线程和后台线程.

向队列中追加任务 dispatch_async和dispatch_sync

dispatch_async(requestHeaderModificationQueue, ^{
           .........
        });
dispatch_sync(requestHeaderModificationQueue, ^{
           .........
        });

使用dispatch_async和dispatch_sync向队列中追加任务.
dispatch_async.异步执行,并不会阻塞当前的线程,而是立即向下执行.
dispatch_sync同步执行,会阻塞当前线程,等待block中的任务执行完毕,程序才会继续向下执行. 所以要避免在主线程中使用dispatch_sync

disaptch_after

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
       ...
    });

上面的代码意思为在5秒后执行block中的任务.
dispatch_after 函数接受三个参数
1.第一个参数是指定时间,用的是 dispatch_time_t 类型的值. 使用dispatch_time 或者 dispatch_walltime函数生成.
dispatch_time函数能够获取从第一个参数dispatch_time_t类型的值,到第二个参数指定的毫秒单位时间后的时间. 如上例,第二个参数为5 * NSEC_PER_SEC毫秒也就是5秒.

2.第二个参数指定要追加任务的队列.

dispatch_group

 dispatch_group_t group = dispatch_group_create()

使用函数dispatch_group_create创建.
dispatch_group同样需要程序员手动的管理引用计数. 同dispatch_queue.
dispatch_group同样有同步执行和异步执行两个函数:dispatch_group_asyncdispatch_group_sync.

dispatch_group_async(<#dispatch_group_t  _Nonnull group#>, <#dispatch_queue_t  _Nonnull queue#>, <#^(void)block#>)

比起dispatch_queue的对出一个参数,指定该block属于指定的dispatch_group_t.

dispatch_group_notify

如果存在多个任务或者多个队列,想要在所有的任务执行完成后,执行指定的操作,可以使用dispatch_group_notify.
dispatch_group_notify会监听指定的group,在所有任务执行完成后,将指定的任务加入指定的队列中.

dispatch_queue_t queue = dispatch_queue_create("xxx.aaa.ccc", DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, queue, ^{
      // ...
    });
    
    dispatch_group_async(group, queue, ^{
       // ...
    });
    
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        
    });
    

dispatch_group_notify

dispatch_group_wait

long result = dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC));
    if (result == 0) {
        NSLog(@"group全部执行");
    }else{
         NSLog(@"group并没有全部执行");
    }

一般来说,线程有三个状态.

  1. 运行,running,此刻线程正在运行
  2. 等待,waiting,此刻线程正在等待某一时间发生,无法执行.
  3. 就绪,ready,此刻线程可以立即执行,但是cpu已经被占用.


    thread_transform.png

操作系统按照优先级或者平均分配给每个线程执行时间. 当该线程分配的时间片未用完之前,线程开始等待某事件, 它就会等待状态. 每当一个线程离开运行状态时,操作系统会选择一个其他的就绪线程立即执行.

dispatch_group_wait函数会使当前线程处于等待状态,并不返回.直到指定的group中的任务全部完成或者指定的时间到达后. 如上例子,group任务全部完成或者5秒之后,函数返回,如果group中的任务全部完成,将会返回0 ,否则返回非0.

当时间指定为DISPATCH_TIME_FOREVER意为永久等待,直到group中的任务全部完成.

dispatch_barrier_sync

dispatch_barrier_sync(queue, ^{
        ...
    });

dispatch_barrier_sync可以理解为栅栏函数,在该block加入队列前加入queue的任务全部执行完之后再去执行该任务. 然后才会执行后面加入的任务. 像一个栅栏一样,把前后的任务隔离开. 可以用来在并发队列中控制任务顺序.

dispatch_suspend和dispatch_resume

队列的挂起以及恢复.

dispatch_semaphore_t

在使用并发队列执行多个任务时,任务的完成时间以及顺序并不能控制,可以使用dispatch_barrier_syncdispatch_group_notify. 这里还有另外一个方法,那就是dispatch_semaphore_t
Dispatch Semaphore 是持有计数的信号,该计数是多线程编程中的计数类型的信号. 在Dispatch Semaphore中,计数为0时等待,计数为大于或者等于1时信号减去1而不对等待.

 dispatch_semaphore_t semphore = dispatch_semaphore_create(1);

  result = dispatch_semaphore_wait(semphore, DISPATCH_TIME_FOREVER);
  
  dispatch_semaphore_signal(semphore);

   dispatch_release(semphore);

以以上代码为例
第一句,创建一个Dispatch Semaphore并且制定信号量为1
第二句,永久等待Dispatch Semaphore的信号量大于0,然后返回.代码乡下执行.
第三句,执行完任务后,将Dispatch Semaphore的计数值加1
第四句,如果该Dispatch Semaphore结束使用,那么手动释放.

dispatch_once_t

 static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        <#code to be executed once#>
    });

dispatch_once函数保证应用程序运行中,即使在多线层环境下,也只执行一次指定的任务.常常用来被使用生成单例.

你可能感兴趣的:(多线程之GCD)