多线程--- GCD

GCD 全称Grand Central Dispatch,是纯C语言,它会自动挂哪里线程的生命周期。

多线程最基本的运行原理就是将任务添加到队列,并且指定执行任务的函数,如下:

    //1:创建串行队列
    dispatch_queue_t queue = dispatch_queue_create("QueueName", DISPATCH_QUEUE_SERIAL);

    //2:创建任务
    dispatch_block_t taskBlock = ^{
        NSLog(@"%@",[NSThread currentThread]);
    };
    //3:利用函数把任务放入队列
    dispatch_sync(queue, taskBlock);

队列分为串行队列和并行队列 ,函数分为 同步函数(dispatch_sync)和异步函数(dispatch_async),队列和函数类型的组合,决定了能都开辟新的线程

  • 同步:必须等待当前语句执行完毕,才会执行下一条语句,不会开启线程。
  • 异步:不用等待当前语句执行完毕就可以执行下一条任务。
  •     a、并行队列 + 异步函数 开启多条线程,不按顺序执行任务;
  •     b、串行队列 + 异步函数 开启一条新线程,按顺序执行任务;
  •     c、主队列 + 异步函数不开启新线程,按顺序执行任务
  •     d、并行队列 + 同步函数不开启新线程,按顺序执行任务;
  •     e、串行队列 + 同步函数不开启新线程,按顺序执行任务;
  •     f、主队列 + 同步函数会出现卡死现象!原因:循环等待,主队列的东西要等主线程执行完,又不能开线程,所以下面的任务要等上面的任务执行完,然后卡死

关于函数与队列的组合Demo,点击此处下载~

还有一种情况的死锁

执行顺序如图所示, 当执行到sync_block的时候,由于是一个同步函数调用的串行队列,同步函数必须要先执行它block 里边的任务3,但是串行队列FIFO原则,3必须等到 4执行后才能执行, 双方相互等待,形成死锁。

关于主队列死锁

    NSLog(@"0");
    dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"1");
    });
    NSLog(@"2");

同步函数调用主队列(主队列不是串行队列但是类似串行队列),同样会造成死锁。

 

栅栏函数

当我们的任务有依赖关系的时候,比如任务1和2执行完毕后才能执行任务3和4,这时候我们可以用到这个函数——栅栏函数。其中 queue 是队列,block 是任务。

dispatch_barrier_sync(dispatch_queue_t queue, dispatch_block_t blcok)

提交一个栅栏函数在同步执行中,它会等待栅栏函数执行完再去执行下一行代码,同步栅栏函数是在主线程中执行的。

dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t blcok)

提交一个栅栏函数在异步执行中,它会立马返回开始执行下一行代码(不用等待任务执行完毕)。

 

 前提:  必须是同一个队列(queue)

注意点: 栅栏函数不能封装异步网络请求,因为异步网络请求不能保证任务在同一个队列上。

共同点

  1. 都会等待自己前边插入的队列的任务(1、2、3)先执行完。
  2. 都会等待他们自己的任务(barrier)执行完后再执行后的任务。

不同点

  1. dispatch_barrier_sync 需要等待自己的任务(barrier)结束之后,才会继续添加并执行写在barrier后边的任务,然后执行。
  2. dispatch_barrier_async将自己的任务(barrier)插入到队列之后,不用等待自己任务的结束,会继续把后边的任务添加到队列中,然后开始执行。
     

调度组

我们经常需要需要监听多个异步任务全部完成后的回调。此时需要用到调度组处理

注意点: 必须是同一个组group

场景:使用异步下载或者请求的时候,等多个任务都执行完时, dispatch_group_notify()监听统一的回调。

基本的调度组执行如下:

    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_group_async(group, queue, ^{
        NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:4 repeats:NO block:^(NSTimer * _Nonnull timer) {
        }];
        [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
        [[NSRunLoop currentRunLoop]run];
    });
    dispatch_group_async(group, queue, ^{
       NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2 repeats:NO block:^(NSTimer * _Nonnull timer) {
        }];
        [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
        [[NSRunLoop currentRunLoop]run];
    });
    dispatch_group_wait(group, 5);  // 最长等待时间
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"--5^^ %@",[NSThread currentThread]); // <= 5秒调用
        
    });

调度组内部方法 enter - leave

    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
        NSLog(@"--1^^ 执行完了,准备出组");
        dispatch_group_leave(group);
    });
    
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
        NSLog(@"--2^^ 执行完了,准备出组");
        dispatch_group_leave(group);
    });
    
    dispatch_group_wait(group, 5);
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"--5^^ %@",[NSThread currentThread]);
    });

 

dispatch_group_enter() 与 dispatch_group_leave  保证成对出现,

dispatch_group_leave 少于dispatch_group_enter(),将不会调用通知, 反之crash;

 

信号量

信号量是用在多线程并发的可控最大任务数量的操作,一个线程完成了某一个动作就通过信号量告诉别的线程,别的线程再进行某些动作

// 创建一个信号,value:信号量
dispatch_semaphore_create(<#long value#>)
// 使某个信号的信号量+1
dispatch_semaphore_signal(<#dispatch_semaphore_t dsema#>)
// 某个信号进行等待或等待降低信号量 timeout:等待时间,永远等待为 DISPATCH_TIME_FOREVER
dispatch_semaphore_wait(<#dispatch_semaphore_t dsema#>, <#dispatch_time_t timeout#>)
正常的使用顺序是先降低然后再提高,这两个函数通常成对使用。
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(2);  // 同时执行任务的数量,不超过2个

      dispatch_async(queue, ^{
          dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
          NSLog(@"执行任务1");
          sleep(1);
          NSLog(@"任务1完成");
          dispatch_semaphore_signal(semaphore);
      });
      
      dispatch_async(queue, ^{
          dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
          NSLog(@"执行任务2");
          sleep(1);
          NSLog(@"任务2完成");
          dispatch_semaphore_signal(semaphore);
      });
    
      dispatch_async(queue, ^{
          dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
          NSLog(@"执行任务3");
          sleep(1);
          NSLog(@"任务3完成");
          dispatch_semaphore_signal(semaphore);
      });
      

dispatch_source

关于source源的设置, 1、2、3 为创建, 4、5、6为设置。

dispatch_source_create

1、创建source源

dispatch_source_set_event_handler

2、设置回调

dispatch_source_merge_data

3、引发回调(绑定source, 带参data)

dispatch_source_get_data

4、获取source绑定的data

dispatch_suspend

5、挂起

dispatch_resume

6.继续

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章