美文网首页
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中线程阻塞

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