美文网首页
多线程之GCD

多线程之GCD

作者: 尽斩桃花三千 | 来源:发表于2018-06-12 16:59 被阅读13次

    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

          本文链接:https://www.haomeiwen.com/subject/lflreftx.html