美文网首页
GCD中线程阻塞

GCD中线程阻塞

作者: sunny冲哥 | 来源:发表于2018-01-22 17:30 被阅读139次

队列:
存放任务的地方,可以理解为存放一段一段要执行的代码。

线程:
执行任务的流程。执行完A,接着执行B,然后再执行C。

任务的执行过程

同步派发必然会导致当前线程被阻塞住,和队列无关。派发函数必须等待任务完成才能返回。

用同步函数往并发队列派发任务时:
任务会当前线程执行。

用同步函数往串行队列派发任务时:
只要调用派发函数时不是在同一串行队列中,就不会阻塞,任务会在当前线程一个一个串行执行,然后派发函数返回。

而异步派发函数比较神奇,不用等待任务完成就可直接返回,因此即使在串行队列中向同一队列异步派发任务,也不会造成死锁,因为派发函数直接就返回了,串行队列中靠后的任务就可以得以执行。至于并发队列,各个任务直接本来就是并发执行的,不存在谁等待谁完成的问题。


同步:
 dispatch_queue_t queue = dispatch_queue_create("thread", DISPATCH_QUEUE_CONCURRENT);
    dispatch_sync(queue, ^{
        NSLog(@"test1");
    });
    dispatch_sync(queue, ^{
        void(^bb)() = ^() {
            sleep(2);
            NSLog(@"延时");
        };
        bb();
        NSLog(@"test2");
    });
    dispatch_sync(queue, ^{
        NSLog(@"test3");
    });
    
    dispatch_barrier_sync(queue, ^{
        //此处耗时,同步因此可能造成卡顿情况
      
        for (NSInteger i = 0; i < 500000000; i++) {
            if (i == 500000)NSLog(@"point1");
            if (i == 600000)NSLog(@"point2");
            if (i == 700000)NSLog(@"point3");
        }
        NSLog(@"barrier");
    });
    NSLog(@"aaa");
    dispatch_sync(queue, ^{
        NSLog(@"test4");
    });
    NSLog(@"bbb");
    dispatch_sync(queue, ^{
        NSLog(@"test5");
    });
    dispatch_sync(queue, ^{
        NSLog(@"test6");
    });

控制台输出:

2018-01-24 10:57:09.654 GCDDemo[3914:3750273] test1
2018-01-24 10:57:11.654 GCDDemo[3914:3750273] 延时
2018-01-24 10:57:11.654 GCDDemo[3914:3750273] test2
2018-01-24 10:57:11.655 GCDDemo[3914:3750273] test3
2018-01-24 10:57:12.868 GCDDemo[3914:3750273] aaa
2018-01-24 10:57:12.868 GCDDemo[3914:3750273] test4
2018-01-24 10:57:12.868 GCDDemo[3914:3750273] bbb
2018-01-24 10:57:12.868 GCDDemo[3914:3750273] test5
2018-01-24 10:57:12.869 GCDDemo[3914:3750273] test6

根据打印时间可以看到是同步执行的,同步的好处是可控制性强,一定是执行完了才往下走,缺点就是如果某一个函数比较耗时的话(此处是手动延时2秒),就会阻塞该线程的执行。


接下来再看dispatch_barrier_syncdispatch_barrier_async
dispatch_barrier_syncdispatch_sync效果几乎一样,顺步执行。
打开上面注释掉的dispatch_barrier_sync,运行,打印结果如下。

2018-01-25 09:56:38.473 GCDDemo[1671:973161] test1
2018-01-25 09:56:40.474 GCDDemo[1671:973161] 延时
2018-01-25 09:56:40.474 GCDDemo[1671:973161] test2
2018-01-25 09:56:40.474 GCDDemo[1671:973161] test3
2018-01-25 09:56:40.476 GCDDemo[1671:973161] point1
2018-01-25 09:56:40.476 GCDDemo[1671:973161] point2
2018-01-25 09:56:40.476 GCDDemo[1671:973161] point3
2018-01-25 09:56:41.650 GCDDemo[1671:973161] barrier
2018-01-25 09:56:41.650 GCDDemo[1671:973161] aaa
2018-01-25 09:56:41.650 GCDDemo[1671:973161] test4
2018-01-25 09:56:41.650 GCDDemo[1671:973161] bbb
2018-01-25 09:56:41.650 GCDDemo[1671:973161] test5
2018-01-25 09:56:41.650 GCDDemo[1671:973161] test6

可以看到打印结果的顺序并没有发生变化。
如果把dispatch_barrier_sync换成dispatch_barrier_async呢?打印结果如下:

2018-01-25 10:22:58.407 GCDDemo[1719:1045532] test1
2018-01-25 10:23:00.408 GCDDemo[1719:1045532] 延时
2018-01-25 10:23:00.408 GCDDemo[1719:1045532] test2
2018-01-25 10:23:00.408 GCDDemo[1719:1045532] test3
2018-01-25 10:23:00.408 GCDDemo[1719:1045532] aaa
2018-01-25 10:23:00.410 GCDDemo[1719:1045691] point1
2018-01-25 10:23:00.410 GCDDemo[1719:1045691] point2
2018-01-25 10:23:00.410 GCDDemo[1719:1045691] point3
2018-01-25 10:23:01.597 GCDDemo[1719:1045691] barrier
2018-01-25 10:23:01.597 GCDDemo[1719:1045532] test4
2018-01-25 10:23:01.598 GCDDemo[1719:1045532] bbb
2018-01-25 10:23:01.598 GCDDemo[1719:1045532] test5
2018-01-25 10:23:01.598 GCDDemo[1719:1045532] test6

可以看出,程序执行到dispatch_barrier_async的时候,没有等待结果返回,直接往下执行,直到遇到dispatch_sync,才会等待dispatch_barrier_async返回结果,再次继续往下执行。



    /**
     异步进程
     test1,2,3,不阻塞线程,并不确定哪个会先执行完.
     
     */
    dispatch_queue_t queue = dispatch_queue_create("thread", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        NSLog(@"test1");
    });
    dispatch_async(queue, ^{
        sleep(2);
        NSLog(@"延时");
        NSLog(@"test2");
    });
    dispatch_async(queue, ^{
        NSLog(@"test3");
    });
    
//    dispatch_barrier_async(queue, ^{
//        for (NSInteger i = 0; i < 500000000; i++) {
//            if (i == 500000)NSLog(@"point1");
//            if (i == 600000)NSLog(@"point2");
//            if (i == 700000)NSLog(@"point3");
//        }
//        NSLog(@"barrier");
//    });
    NSLog(@"aaa");
    dispatch_async(queue, ^{
        NSLog(@"test4");
    });
    NSLog(@"bbb");
    dispatch_async(queue, ^{
        NSLog(@"test5");
    });
    dispatch_async(queue, ^{
        NSLog(@"test6");
    });
    
    return;
    dispatch_sync(queue, ^{
        NSLog(@"1");
    });
    dispatch_sync(queue, ^{
        NSLog(@"2");
    });
    dispatch_sync(queue, ^{
        NSLog(@"3");
    });
    dispatch_sync(queue, ^{
        NSLog(@"4");
    });
2018-01-24 11:11:29.320 GCDDemo[4002:3827389] aaa
2018-01-24 11:11:29.320 GCDDemo[4002:3832535] test1
2018-01-24 11:11:29.320 GCDDemo[4002:3837535] test3
2018-01-24 11:11:29.320 GCDDemo[4002:3827389] bbb
2018-01-24 11:11:29.320 GCDDemo[4002:3837536] test4
2018-01-24 11:11:29.321 GCDDemo[4002:3837535] test5
2018-01-24 11:11:29.321 GCDDemo[4002:3832535] test6
2018-01-24 11:11:31.324 GCDDemo[4002:3837525] 延时
2018-01-24 11:11:31.324 GCDDemo[4002:3837525] test2

可以看到异步的时候,每一个进程执行相互是不影响的。这种模式比较常见的就是网络解析图片的时候,异步解析,主线程加载图片。不阻塞线程,但是还有一个问题就是,程序可控性较差,有时候可能得不到结果。比如C要获得到A的结果才能正常执行,但是A还没有执行完毕的时候,C可能就执行了。

  1. 再来看dispatch_barrier_async,打开上面的注释,看一下打印结果:
2018-01-25 10:44:03.021 GCDDemo[1767:1097902] aaa
2018-01-25 10:44:03.021 GCDDemo[1767:1100068] test1
2018-01-25 10:44:03.021 GCDDemo[1767:1100069] test3
2018-01-25 10:44:03.021 GCDDemo[1767:1097902] bbb
2018-01-25 10:44:05.024 GCDDemo[1767:1098660] 延时
2018-01-25 10:44:05.024 GCDDemo[1767:1098660] test2
2018-01-25 10:44:05.026 GCDDemo[1767:1098660] point1
2018-01-25 10:44:05.026 GCDDemo[1767:1098660] point2
2018-01-25 10:44:05.026 GCDDemo[1767:1098660] point3
2018-01-25 10:44:06.300 GCDDemo[1767:1098660] barrier
2018-01-25 10:44:06.300 GCDDemo[1767:1100069] test4
2018-01-25 10:44:06.300 GCDDemo[1767:1100068] test5
2018-01-25 10:44:06.300 GCDDemo[1767:1100068] test6

可以看出代码执行不受影响,不用等待其他代码执行完成,各走各的。

  1. 换成dispatch_barrier_sync,再看一下打印结果
2018-01-25 14:57:29.253 GCDDemo[2189:1798062] test1
2018-01-25 14:57:29.254 GCDDemo[2189:1798689] 延时
2018-01-25 14:57:29.254 GCDDemo[2189:1798063] test3
2018-01-25 14:57:29.254 GCDDemo[2189:1798689] test2
2018-01-25 14:57:29.255 GCDDemo[2189:1796600] point1
2018-01-25 14:57:29.256 GCDDemo[2189:1796600] point2
2018-01-25 14:57:29.256 GCDDemo[2189:1796600] point3
2018-01-25 14:57:30.419 GCDDemo[2189:1796600] barrier
2018-01-25 14:57:30.420 GCDDemo[2189:1796600] aaa
2018-01-25 14:57:30.420 GCDDemo[2189:1796600] bbb
2018-01-25 14:57:30.420 GCDDemo[2189:1798689] test4
2018-01-25 14:57:30.420 GCDDemo[2189:1798689] test5
2018-01-25 14:57:30.420 GCDDemo[2189:1798063] test6

可以看出,在插入位置前面的代码,不受影响,各走各的,但是插入位置之后的,就必须等待dispatch_barrier_sync中的代码执行完毕才能执行。


dispatch_barrier_async 和 dispatch_barrier_sync区别
总结:
简单来说,就是asyn不阻塞当前线程而已,barrier只是阻塞同队列中后面的操作而已

相关文章

  • GCD死锁

    GCD死锁原因 GCD死锁的原因是队列阻塞,而不是线程阻塞! 串行和并行 串行和并行都是相对于队列而言的-队列(负...

  • GCD中线程阻塞

    队列:存放任务的地方,可以理解为存放一段一段要执行的代码。 线程:执行任务的流程。执行完A,接着执行B,然后再执行...

  • GCD的线程阻塞

    A、dispatch_semaphore信号量: 如果初始化的时候信号量为0,并且执行任务的过程中,没有发送信号,...

  • IOS基础之切回到主线程的N种方式

    方式一:GCD (最常用) 使用GCD又有2种方式:异步回到主线程和同步回到主线程。2种方式的差别在于是否会阻塞原...

  • IOS基础之切回到主线程的N种方式

    方式一:GCD (最常用) 使用GCD又有2种方式:异步回到主线程和同步回到主线程。2种方式的差别在于是否会阻塞原...

  • iOS GCD知识

    为什么要用GCD 更好的利用多核、更好的利用并发 什么时候用到GCD 解决耗时、阻塞主队列(主线程)、完成并发任务...

  • Java基础面试高频问答题

    1、什么导致线程阻塞 一般线程中的阻塞: Socket客户端的阻塞: Socket服务器的阻塞: 什么导致线程阻塞...

  • 7.3 多线程-GCD

    多线程-GCD 多线程-GCD-串行并行 多线程-GCD.png GCD-线程的通讯、延时操作、定时器 GCD-线...

  • GCD中的串行,并行,同步,异步详解

    gcd中的串行,并行,同步,异步详解 1、gcd中同步与异步的区别: gcd中的线程是由一个线程池来管理的,这个池...

  • GCD

    GCD(Grand Central Dispatch) GCD 中其实没有线程的说法,只有队列的说法。习惯使用线程...

网友评论

      本文标题:GCD中线程阻塞

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