1010cc时时彩标准版 > 操作系统 > 1010cc时时彩标准版:iOS中GCD学习笔记,多线程技

原标题:1010cc时时彩标准版:iOS中GCD学习笔记,多线程技

浏览次数:164 时间:2019-08-09

iOS二十四线程支付之GCD(下篇),ios二十四线程gcd下篇

     上篇和中篇解说了哪些是GCD,怎么样利用GCD,那篇小说将教师使用GCD上将遭逢的死锁难题。有意思味的相恋的人可以纪念《iOS八线程开拓之GCD(上篇)》和《iOS多线程开垦之GCD(中篇)》。

     言归正传,我们第一来回想下死锁,所谓死锁: 是指八个或八个以上的经过(线程)在实施进度中,因争夺能源(如数据源,内部存款和储蓄器等,变量不是能源)而致使的一种相互等待的场所,若无外界管理效果,它们都将无限等待下去。

  死锁产生的来由:

  死锁造成的口径:

     

      在GCD中,首要的死锁就是时下串行队列之中同步执行当前串行队列。化解的主意正是将一并的串行队列放到另外叁个线程推行。在譬喻说明从前,我们先来回想下GCD的中的职分派发和队列。

    (1)任务派发

任务派发方式 说明
dispatch_sync() 同步执行,完成了它预定的任务后才返回,阻塞当前线程
dispatch_async() 异步执行,会立即返回,预定的任务会完成但不会等它完成,不阻塞当前线程

    (2)队列系列

队列种类 说明
串行队列 每次只能执行一个任务,并且必须等待前一个执行任务完成
并发队列 一次可以并发执行多个任务,不必等待执行中的任务完成

     (3)GCD队列种类

GCD队列种类 获取方法 队列类型 说明
主队列 dispatch_get_main_queue 串行队列 主线中执行
全局队列 dispatch_get_global_queue 并发队列 子线程中执行
用户队列 dispatch_queue_create 串并都可以 子线程中执行

       由此大家得以摄取:串行与互为针对的是队列,而共同与异步,针对的则是线程!

       

      在GCD中,首要的死锁正是现阶段串行队列之中同步推行业前串行队列。消除的主意正是将协同的串行队列放到别的贰个线程实行。在举例表达从前,大家先来回看下GCD的中的任务派发和队列。

  死锁变成的案由:

前言:
很早以前就想总括一下多线程那块,在职业中平时使用,特别是当今付出的一款跟图片管理相关的利用,多线程的重大就尤其杰出。
那篇文章希图总结一些 GCD 的一些概念和在开垦中一些常用方法。

7. 案例与分析

问题1:在主线程中调用,以下代码结果是何等?

    NSLog(@"1"); //任务1
    dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"2"); //任务2
    });
    NSLog(@"3"); //任务3

支配台出口

1

结果深入分析

  1. dispatch_sync表示是三个同步线程,会堵塞当前线程,然后把Block中职分加多到行列中实施,等到Block中职务达成后才会让日前线程继续试行。
  2. dispatch_get_main_queue表示主线程中的主队列;

首先推行职分1,打字与印刷出1,程序遭遇dispatch_sync会立刻阻塞当前主线程,把职责2放到主队列中, 等待职责2实行完,再举办职分3。但是主队列是根据FIFO原则实行职务,此时主队列中职责3排在职务2事先,所以要等到任务3推行完后本事进行义务2,那就能导致他们步向互相等待的框框,进而暴发死锁。制止死锁的法子是在使用dispatch_sync实行职分时,传入参数的行列不要和当下线程的行列是一律的

问题2:以下代码的输出结果是何许?

 dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL);
    NSLog(@"1"); //任务1
    dispatch_async(queue, ^{
        NSLog(@"2"); //任务2
        dispatch_sync(queue, ^{
            NSLog(@"3"); //任务3
        });
        NSLog(@"4"); //任务4
    });
    NSLog(@"5"); //任务5

支配台出口

1
5
2
5和2的各样不断定

结果分析

  1. 第一自定义创造了一个串行队列(DISPATCH_QUEUE_SERIAL)。
  2. 实行职务1,打印出1。
  3. dispatch_async 是异步推行,所以当前线程不会被堵塞,会别的开启一个新线程,于是当前有五个线程在运转,管他们叫主线程和辅线程。
  4. 主线程继续实施职分5,打字与印刷出5。
  5. 辅线程施行Block中的任务。而Block中的职分和上二个例证问题1是均等的。能够遵循上个例子方法剖析,只会进行任务2,打字与印刷出2。由于主线程和辅线程是异步试行的,所以5和2没有先后顺序。

  6. GCD别的一些特征

  • 巡回实行义务
    dispatch_apply类似二个for循环,并发的实行每一项。全体职务完成后,dispatch_apply才会回来,会卡住当前线程。即使传入队列是串行队列,要留意防御死锁现象的发生。
//循环执行任务,任务的顺序是无序列的并且会堵塞当前的线程。
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    // count: 循环执行次数
    // queue: 队列,可以是串行队列或者是并行队列
    // block: 任务
    dispatch_apply(count, queue, ^(size_t i) {
        NSLog(@"%zu %@", i, [NSThread currentThread]);
    });
  • 队列组
    队列组将很多队列增添到二个组里,当组里装有职分都实践完后,它会由此二个方法通告大家。基本流程是率先成立三个队列组,然后把职分加多到组中,最后等待队列组的实施结果。
//创建队列组
    dispatch_group_t group = dispatch_group_create();
    //创建队列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    //将执行任务添加到队列组中, 队列组只有异步方法能添加任务
    //执行3次循环
    dispatch_group_async(group, queue, ^{
        for (NSInteger i = 0; i < 3; i  ) {
            NSLog(@"group-01 - %@", [NSThread currentThread]);
        }
    });

    //主队列执行8次循环
    dispatch_group_async(group, dispatch_get_main_queue(), ^{
        for (NSInteger i = 0; i < 5; i  ) {
            NSLog(@"group-02 - %@", [NSThread currentThread]);
        }
    });

    //都完成后会自动通知
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"完成 - %@", [NSThread currentThread]);
    });
  • dispatch_once_t完成单例格局
static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        //dispatch_once中的代码只执行一次,常用来实现单例
        //创建实例变量

    });
  • GCD延迟操作
//创建队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//设置延时,单位秒
double delay = 3; 

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), queue, ^{
    //3秒后需要执行的任务
});

仿照效法资料:
1.乌棒哥的iOS十六线程相关学习笔记
2.GCD
3.iOS中GCD的施用小结
4.iOS多线程GCD简介
5.GCD介绍
6.GCD基础知识集合
7.关于iOS四线程,你看自身就够了
8.Concurrency Programming Guide

     案例深入分析:

        一、同步实行碰着串行队列

- (void)syncMain{

    dispatch_queue_t queue = dispatch_get_main_queue();

    NSLog(@"task1-%@",[NSThread currentThread]);

    dispatch_sync(queue, ^{
        NSLog(@"task2-%@",[NSThread currentThread]);
    });

    NSLog(@"task3-%@",[NSThread currentThread]);
}

       打字与印刷结果:

2017-07-10 17:54:43.623 beck.wang[1405:182548] task1-<NSThread: 0x608000066000>{number = 1, name = main}

      分析:死锁。

      原因:从打印结果能够看到,task1是在主线程中实践,而主线程是串行队列,定义的queue队列也是主队列, dispatch_sync是同台实践的标识,意思是必须等待block再次回到,技巧试行task3,而近期主队列中正在被task1实施,必须等待完毕task3到位后技巧放出,那就导致了task3等待block完结重临,block等待task3造成自由主队列而互相等待的轮回中死锁。

      扩展:在主线程使用sync函数就能够形成死锁”可能“在主线程使用sync函数,同一时候传入串行队列就能够死锁”吗? NO,这种表达分明是不曾真的理解死锁!从地点的案例中我们很显著的知道,死锁发生的缘由是队列的梗塞。那么只要自个儿自定义一个串行队列,不与主队列争宠呢?

- (void)syncMain{

    // 注意这里的queue是自定义的串行队列,而不是主队列dispatch_get_main_queue()
    dispatch_queue_t queue = dispatch_queue_create("com.demo.serialQueue", DISPATCH_QUEUE_SERIAL);

    NSLog(@"task1-%@",[NSThread currentThread]);

    dispatch_sync(queue, ^{

        NSLog(@"task2-%@",[NSThread currentThread]);
    });

    NSLog(@"task3-%@",[NSThread currentThread]);
}

       打字与印刷结果:

2017-07-10 18:07:15.134 beck.wang[1427:192164] task1-<NSThread: 0x600000074800>{number = 1, name = main}
2017-07-10 18:07:15.135 beck.wang[1427:192164] task2-<NSThread: 0x600000074800>{number = 1, name = main}
2017-07-10 18:07:15.135 beck.wang[1427:192164] task3-<NSThread: 0x600000074800>{number = 1, name = main}

      解析:不开启新线程,顺序试行。

      原因:task1、task3与task2试行的行列不均等,不会堵塞。

 

      二、同步施行境遇并行队列

- (void)syncConcurrent{

    NSLog(@"task11-%@",[NSThread currentThread]);

    dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"task12-%@",[NSThread currentThread]);
    });

    NSLog(@"task13-%@",[NSThread currentThread]);
}

     打字与印刷结果:

2017-07-10 18:15:11.957 beck.wang[1452:198567] task11-<NSThread: 0x608000071f00>{number = 1, name = main}
2017-07-10 18:15:11.957 beck.wang[1452:198567] task12-<NSThread: 0x608000071f00>{number = 1, name = main}
2017-07-10 18:15:11.957 beck.wang[1452:198567] task13-<NSThread: 0x608000071f00>{number = 1, name = main}

     剖判:不开启新线程,顺序实行。

     原因:task1、task3与task2实行的类别分裂样,不会阻塞。

     

     三、异步&同步组合

- (void)gcdTest{

    dispatch_queue_t queue = dispatch_queue_create("com.demo.serialQueue", DISPATCH_QUEUE_SERIAL);

    NSLog(@"task1-%@",[NSThread currentThread]);

    dispatch_async(queue, ^{

        NSLog(@"task2-%@",[NSThread currentThread]);

        dispatch_sync(queue, ^{
            NSLog(@"task3-%@",[NSThread currentThread]);
        });

        NSLog(@"task4-%@",[NSThread currentThread]);
    });

    NSLog(@"task5-%@",[NSThread currentThread]);
}

 

     打字与印刷结果:

2017-07-10 18:29:23.976 beck.wang[1562:207413] task1-<NSThread: 0x608000063400>{number = 1, name = main}
2017-07-10 18:29:23.976 beck.wang[1562:207413] task5-<NSThread: 0x608000063400>{number = 1, name = main}
2017-07-10 18:29:23.976 beck.wang[1562:207460] task2-<NSThread: 0x608000067940>{number = 3, name = (null)}

     分析:死锁。

     原因:task2、task4与task3在同一队列中举办,dispatch_sync分明了task4须要拭目以俟task3完结后回去工夫推行,而task2职务奉行的时候已经占领了现阶段队列,供给等到task4完毕后技艺自由,那就导致了task3等候task4达成,task4等待task3回来的交互等待,那也是队列阻塞导致的死锁。

     扩展:要是queue换到自定义并发队列或许dispatch_sync追加到非当前队列(如主队列),则不会时有爆发死锁。

- (void)gcdTest{

    dispatch_queue_t queue = dispatch_queue_create("com.demo.serialQueue", DISPATCH_QUEUE_SERIAL);

    NSLog(@"task1-%@",[NSThread currentThread]);

    dispatch_async(queue, ^{

        NSLog(@"task2-%@",[NSThread currentThread]);

        // 这里使用主队列,而非自定义的串行队列,则不会发生死锁,同理并行队列也不会死锁
        dispatch_sync(dispatch_get_main_queue(), ^{
            NSLog(@"task3-%@",[NSThread currentThread]);
        });

        NSLog(@"task4-%@",[NSThread currentThread]);
    });

    NSLog(@"task5-%@",[NSThread currentThread]);
}

     打字与印刷结果:

2017-07-10 18:38:20.214 beck.wang[1582:215721] task1-<NSThread: 0x608000069780>{number = 1, name = main}
2017-07-10 18:38:20.214 beck.wang[1582:215721] task5-<NSThread: 0x608000069780>{number = 1, name = main}
2017-07-10 18:38:20.214 beck.wang[1582:215779] task2-<NSThread: 0x618000069cc0>{number = 3, name = (null)}
2017-07-10 18:38:20.217 beck.wang[1582:215721] task3-<NSThread: 0x608000069780>{number = 1, name = main}
2017-07-10 18:38:20.217 beck.wang[1582:215779] task4-<NSThread: 0x618000069cc0>{number = 3, name = (null)}

 

    四、下边包车型大巴扩大案例中,主线程阻塞。

- (void)gcdTest{

    dispatch_queue_t queue = dispatch_queue_create("com.demo.serialQueue", DISPATCH_QUEUE_SERIAL);

    NSLog(@"task1-%@",[NSThread currentThread]);

    dispatch_async(queue, ^{

        NSLog(@"task2-%@",[NSThread currentThread]);

        // 这里虽然使用主队列,但主队列已经阻塞,后续代码失效
        dispatch_sync(dispatch_get_main_queue(), ^{
            NSLog(@"task3-%@",[NSThread currentThread]);
        });

        NSLog(@"task4-%@",[NSThread currentThread]);
    });

    NSLog(@"task5-%@",[NSThread currentThread]);

    while (1) {
        // 进入while的恒等循环,主线程(主队列)阻塞
    }

    NSLog(@"task6-%@",[NSThread currentThread]);
}

       打字与印刷结果:

2017-07-10 18:47:22.844 beck.wang[1657:223045] task1-<NSThread: 0x60000007afc0>{number = 1, name = main}
2017-07-10 18:47:22.844 beck.wang[1657:223045] task5-<NSThread: 0x60000007afc0>{number = 1, name = main}
2017-07-10 18:47:22.844 beck.wang[1657:223110] task2-<NSThread: 0x610000262700>{number = 3, name = (null)}

     深入分析:主线程步向无限阻塞状态task6、task3、task4都不能够访问到,处于最棒等待情形。

 

     PS:那篇小说有借鉴部分,笔者写那篇博文的指标也是为着越来越好的接头GCD的死锁,毕竟好记性不比烂笔头嘛!在工作中作者也会持续完毕际遇的GCD的死锁情形,SO,本篇小说未完待续.....

 

上篇和中篇讲授了什么样是GCD,怎样行使GCD,那篇小说将教师使用GCD中将蒙受的死锁难题。有兴...

  死锁变成的尺度:

    (1)职务派发

GCD 的局地用法

回顾起见,各个直接列出来吧。前面几条是大范围的线程操作函数,前面几条也是常事使用的 GCD 的用法。

2. Grand Central Dispatch(GCD)基本概念

GCD是苹果对多核的互动运转一种缓和方案。
优点:依赖C语言,轻巧易用,功用高,速度快,会自动管理线程生命周期,开垦者只需关怀GCD要实行的天职和队列。
缺点: 当GCD的现象复杂时,只怕会遭遇死锁。

任务派发方式 说明
dispatch_sync() 同步执行,完成了它预定的任务后才返回,阻塞当前线程
dispatch_async() 异步执行,会立即返回,预定的任务会完成但不会等它完成,不阻塞当前线程

     上篇和中篇批注了什么是GCD,怎么样利用GCD,那篇小说将助教使用GCD中将境遇的死锁难点。有意思味的心上人可以记念《iOS八线程开垦之GCD(上篇)》和《iOS二十四线程支付之GCD(中篇)》。

(10)dispatch_sync抓住的死锁

1010cc时时彩标准版,6. 把职分添加到行列中

  • 一同职分
dispatch_sync(<#queue#>, ^{
      //Task
      NSLog(@"Do some work here.");
  });
  • 异步职责
dispatch_async(<#queue#>, ^{
      //Task
      NSLog(@"Do some work here.");
  });
  1. 互斥条件:所谓互斥就是进度在某有时间内独占能源。
  2. 须求与保证标准:八个历程因伏乞财富而围堵时,对已猎取的能源保持不放。
  3. 不剥夺条件:进程已获取财富,在末使用完以前,不能强行剥夺。
  4. 巡回等待条件:若干经过之间形成一种头尾相接的巡回等待财富事关。
  1. 系统财富不足
  2. 进度(线程)推进的相继不稳当;
  3. 能源分配不当
上边这么些事例能够跟下面前境遇比一下
- (void)viewDidLoad {
    [super viewDidLoad];
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
    NSLog(@"==>1");
    dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"==>2");
    });
    NSLog(@"==>3");
});
}

async 立刻回到,viewDidLoad 推行达成,即主线程实行完成。
还要,全局并发队列立时实践异步 block ,打字与印刷 1,当试行到 sync 它会等待 block 施行到位才回来。而此时 main_queue 中的职分已经停止(借使主线程操作很多这么些串行队列会多走一会儿),直接试行了 Block 中的内容,从而 sync 函数成功重回。程序继续往下走未有毛病。(打字与印刷1,2,3)可是只要对代码进行多少修改。想想会发生怎么样:

- (void)viewDidLoad {
    [super viewDidLoad];

    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"==>1");
        dispatch_sync(dispatch_get_main_queue(), ^{
            NSLog(@"==>2");
        });
        NSLog(@"==>3");
    });
    while (1) {
    }
}

简单看出,main_queue 中的 block 代码会平素等着主线程操作达成能力推行。而 sync 一向等着 block 的实行到位。恰巧此时的主线程陷入Infiniti循环中难以自拔,所以程序仅仅打字与印刷了 1,然后就陷入了势不两立中。

串行和产出

串行:叁个职务实行完成后,再举办下二个职责
出现:允许四个任务同期实施

本文由1010cc时时彩标准版发布于操作系统,转载请注明出处:1010cc时时彩标准版:iOS中GCD学习笔记,多线程技

关键词:

上一篇:Agent客户端的编译安装,Zabbix自动发现批量添加主

下一篇:没有了