• 关于GCD使用


      在各种书籍资料中看到关于GDC中容易死锁的调用

    一、

    -(void)test{

      dispatch_sync(dispatch_get_main_queue(), ^{NSLog(@"Hello World");});

    }

    这样的调用会造成死锁,但是没解释清楚为什么不能这样调用。下面就以来说明原因:

    由于主队列是先进先出,等待上一个结束才能执行下一个任务.在主线程中调用test函数,这样test就会进入主队列中这个步骤叫A,当在主队列中执行dispatch_sync(dispatch_get_main_queue(), ^{NSLog(@"Hello ?");});的时候又会往主队列中加入一个任务这个任务叫B,由于在队列中A还没有执行完所以B要等待A

    执行完才能执行,但是A要执行完要先执行完B任务,这样就造成互相等待出现死锁。

    1 主线程执行test函数(A操作)

    2 将A加入主队列

    3 在执行A的时候又调用了dispatch_sync函数(B操作)将B加入主队列

    4  这样主队列中就有 B-A两个任务

    5 由于A一直没有执行完不能出队列(因为B执行完A才能出队列, 然而B在队列中根本没执行因为根据先进先出的规则A先进队列,所以B排在A后面执行)

    所以就造成互相等待造成死锁。

     

    二、

     

    -(void)testThread{

        dispatch_queue_t queue = dispatch_get_main_queue();

        dispatch_async(queue, ^{

            dispatch_sync(dispatch_get_main_queue(), ^{

                NSLog(@"1");

            });

         });

        NSLog(@"ok");

    }

    在object-c高级编程中这个调用也会死锁。参考一下列表

     

    这里都是用的主队列,虽然用的是异步函数,但是根据上表主队列都是在主线程中执行的,所以参考第一个列子也很容易得出死锁的原因

    如果将主队列换成全局队列或是手动创建队列则不会出现死锁。 

     

    三、

     

    -(void)testThread2{

         dispatch_queue_t queue = dispatch_queue_create("com.hype.threadtest", NULL);

             dispatch_async(queue, ^{

             dispatch_sync(queue, ^{

                 NSLog(@"1");

            });

         });

         NSLog(@"ok");

     }

    这样调用虽然没出现死锁但是NSLog(@"1")却没有执行,原因不清楚,有待研究。

     

    总结:如果要避免出现死锁,那么绝对不要给运行在同一队列中得任务调用 dispatch_sync或是 dispatch_sync_f函数

    四、

    dispatch_queue_t queue = dispatch_queue_create("com.liancheng.serial_queue", DISPATCH_QUEUE_SERIAL);
     
    dispatch_async(queue, ^{
        // 到达串行队列
         
        dispatch_sync(queue, ^{     //发生死锁
         
        });
    });

    dispatch_sync需要等待block执行完成,同时由于队列串行,block的执行需要等待前面的任务,也就是dispatch_sync执行完成。两者互相等待,永远也不会执行完成,死锁就这样发生了

    从这里看发生死锁需要2个条件:

    1. 代码运行的当前队列是串行队列

    2. 使用sync将任务加入到自己队列中

    如果queue是并行队列,或者将任务加入到其他队列中,这是不会发生死锁的。

    五 、

    不管在哪个线程中只要使用了dispatch_get_main_queue()队列都会转到主线程中去执行

        dispatch_queue_t globalQueue = dispatch_queue_create("com.liancheng.global_queue", DISPATCH_QUEUE_SERIAL);

        dispatch_async(globalQueue, ^{

            NSLog(@"current thread1:%@", [NSThread currentThread]);

            dispatch_async(dispatch_get_main_queue(), ^{

                   NSLog(@"current thread2:%@", [NSThread currentThread]);

            });

            NSLog(@"current thread3:%@", [NSThread currentThread]);

        });

        NSLog(@"this is main queue:%@ ", [NSThread currentThread]);

     

  • 相关阅读:
    Linux 环境变量 设置 etc profile
    Linux 升级glibc-2.14 失败 我遇到的问题
    qt窗口的切换
    qt事件机制---事件范例
    qt中的事件机制
    qt的信号与槽函数
    linux下qt的安装
    qt中的udp编程
    qt中的tcp编程
    qt中的多线程
  • 原文地址:https://www.cnblogs.com/HypeCheng/p/4500972.html
Copyright © 2020-2023  润新知