GCD

https://www.jianshu.com/p/77c5051aede2

\color{red}{注释}: GCD的两个核心概念:任务和队列

  • 任务:执行什么操作
  • 队列:用来存放任务,分为:并行队列和串行队列
  并行队列:
         可以让多个任务并发执行,以提高执行效率
         并发功能仅在异步(dispatch_async)函数下才有效
  串行队列:
         在当前线程中让任务一个接着一个地执行

1.创建队列

// 队列类型
dispatch_queue_t
// 第一个参数:队列名称  第二个参数:队列类型
dispatch_queue_create(const char *label, dispatch_queue_attr_t attr);
  // 队列类型
  // 串行队列标识:本质就是NULL,但建议不要写成NULL,可读性不好
  DISPATCH_QUEUE_SERIAL
  // 并行队列标识
  DISPATCH_QUEUE_CONCURRENT
1.1 创建并行队列的两种方式
  • 第一种
    dispatch_queue_t queue = dispatch_queue_create("yanhooQueue", DISPATCH_QUEUE_CONCURRENT);
    
  • 第二种
    // 第一个参数:队列优先级
    // 第二个参数:保留参数,暂时无用,用0即可
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    // 全局并发队列的优先级
    #define DISPATCH_QUEUE_PRIORITY_HIGH 2               // 高
    #define DISPATCH_QUEUE_PRIORITY_DEFAULT 0            // 默认(中)
    #define DISPATCH_QUEUE_PRIORITY_LOW (-2)             // 低
    #define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 后台
    
1.2 创建串行队列的两种方式
  • 第一种
  // 创建串行队列(队列类型传递DISPATCH_QUEUE_SERIAL或者NULL)
  dispatch_queue_t queue = dispatch_queue_create("yanhooQueue", DISPATCH_QUEUE_SERIAL);
  • 第二种
  // 主队列中的任务,都会放到主线程中执行
  dispatch_queue_t queue = dispatch_get_main_queue();

—————————————————————————————————————————————

2.同步(sync)函数 \color{red}{和} 异步(async)函数

  • 函数作用:将任务添加到队列中
  • 函数类型:决定是否有开启新线程的能力

2.1 同步函数:不具备开启新线程的能力,只能在当前线程中执行任务
// queue:队列
// block:任务
dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
2.2异步函数:具备开启线程的能力,但不一定开启新线程,比如:当前队列为主队列,异步函数也不会开启新的线程
// queue:队列
// block:任务
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);

\color{red}{\Large{经验总结}}

  • 通过异步函数添加任务到队列中,任务不会立即执行
  • 通过同步函数添加任务到队列中,任务会立即执行

—————————————————————————————————————————————

3.程序猿只需要做下列事情

  • 3.1 创建队列(是否具备开起新线程能力)
  • 3.2 指定队列类型(同步异步)
base.png

—————————————————————————————————————————————

4.实战

  • 4.1 并行队列+异步函数 (开启多条子线程,任务并行执行
- (void)asyncConcurrent{
    // 1.创建并行队列
//    dispatch_queue_t queue = dispatch_queue_create("yanhooQueue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    // 2.通过异步函数将将任务加入队列
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i<10; i++) {
            NSLog(@"1-----%@", [NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i<10; i++) {
            NSLog(@"2-----%@", [NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i<10; i++) {
            NSLog(@"3-----%@", [NSThread currentThread]);
        }
    });
    // 证明:异步函数添加任务到队列中,任务【不会】立即执行
    NSLog(@"asyncConcurrent--------end");

    // 释放队列,ARC中无需也不允许调用这个方法
//    dispatch_release(queue);
}
  • 4.2 串行队列+异步函数 (开启一条子线程,任务是有序的在子线程上执行)
- (void)asyncSerial{
    // 1.创建串行队列
    dispatch_queue_t queue = dispatch_queue_create("yanhooQueue", DISPATCH_QUEUE_SERIAL);
//    dispatch_queue_t queue = dispatch_queue_create("yanhooQueue", NULL);
    // 2.通过异步函数将任务加入队列
    dispatch_async(queue, ^{
        NSLog(@"1-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"2-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"3-----%@", [NSThread currentThread]);
    });
    // 证明:异步函数添加任务到队列中,任务【不会】立马执行
    NSLog(@"asyncConcurrent--------end");
}
  • 4.3 主队列+异步函数 (不开启子线程,任务是在主线程中有序执行)
- (void)asyncMain{
    // 1.获得主队列
    dispatch_queue_t queue = dispatch_get_main_queue();
    // 2.通过异步函数将任务加入队列
    dispatch_async(queue, ^{
        NSLog(@"1-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"2-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"3-----%@", [NSThread currentThread]);
    });
}
  • 4.4 并行队列+同步函数(不会开启子线程,任务是有序执行)
- (void)syncConcurrent{
    // 1.获得全局的并发队列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    // 2.通过同步函数将任务加入队列
    dispatch_sync(queue, ^{
        NSLog(@"1-----%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"2-----%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"3-----%@", [NSThread currentThread]);
    });
    // 证明:同步函数添加任务到队列中,任务【立马执行】
    NSLog(@"syncConcurrent--------end");
}
  • 4.5 串行队列+同步函数(不会开启线程,任务是有序执行)

\color{red}{注:易发生死锁}

  • 下面的用法会发生死锁吗?
- (void)syncMain{
    // 1.创建串行队列
    dispatch_queue_t queue = dispatch_queue_create("yanhooQueue", DISPATCH_QUEUE_SERIAL);
    // 2.将任务加入队列
    dispatch_sync(queue, ^{
        NSLog(@"1-----%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"2-----%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"3-----%@", [NSThread currentThread]);
    });
}
  • 答案:上面的用法不会发生死锁,原因分析如下
    • 虽然都是在主线程上执行的,但任务在不同的队列中所以不会发生阻塞
    • \color{red}{\Large{syncMain}}函数是在主队列中
    • 其他的任务是在新建的串行队列中
  • 4.5.2 \color{red}{\Large{死锁的几中场景}}
dispatch_queue_t queue = dispatch_queue_create("yanhooQueue", DISPATCH_QUEUE_SERIAL);
dispatch_sync(queue, ^{
       NSLog(@"1-----%@", [NSThread currentThread]);
       // 这里阻塞了
       dispatch_sync(queue, ^{
             NSLog(@"2-----%@", [NSThread currentThread]);
       });
});
  - (void)syncMain  {
      // 获得主队列
      dispatch_queue_t queue = dispatch_get_main_queue();
      // 这里阻塞了
      dispatch_sync(queue, ^{
          NSLog(@"1-----%@", [NSThread currentThread]);
      });
      dispatch_sync(queue, ^{
          NSLog(@"2-----%@", [NSThread currentThread]);
      });
      dispatch_sync(queue, ^{
          NSLog(@"3-----%@", [NSThread currentThread]);
      });
  }
  • 同步函数在任务执行过程中往任务所在的串行队列中添加任务就会导致任务间互相等待,造成死锁
  • 别忘了同步函数添加任务到队列中,任务会立即执行,如果是异步函数就不会发生死锁

—————————————————————————————————————————————

5.GCD实现线程间通信

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容