在各种书籍资料中看到关于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个条件:
-
代码运行的当前队列是串行队列
-
使用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]);