首先声明2个串行队列A,B
-(void)viewDidLoad
{
[super viewDidLoad];
//初始化串行队列A,B
A = dispatch_queue_create("A", DISPATCH_QUEUE_SERIAL);
B = dispatch_queue_create("B", DISPATCH_QUEUE_SERIAL);
test1();
}
void test1()
{
dispatch_async(A, ^{
test2(); //任务T1
});
NSLog(@"test1 called");
}
void test2()
{
dispatch_sync(B, ^{
test3(); //任务T2
});
NSLog(@"test2 called");
}
void test3()
{
dispatch_sync(A, ^{
int a = 3; //任务T3
});
NSLog(@"test3 called");
}
运行程序后,结果为:
只输出了“test1 called”,为什么?
从头分析下这段代码,在test1,test2,test3函数里面分别加断点如下所示:
调试过程中,test3中的block不会进入,原因在于test2与test3中的两个block导致的死锁。
程序运行到test1时,向队列A异步派发一个block任务T1,所以test1中不等待dispatch_async()函数返回就继续向下执行,输出”test1 called”。
当执行队列A中的block任务T1时,调用test2函数,向队列B中同步派发一个任务T2,等待B中的任务T2执行完再向下执行,B中的任务是调用test3函数,继续向A中分派一个任务T3,等待T3执行完再向下执行,而串行队列中的任务是先进先出,此时队列A中已经有一个任务T1在执行,必须等待T1执行完,T3才能开始执行;而T1要等待T2执行完,T2要等待T3执行完,T3要等待T1执行完,所以造成死锁。
为什么只打印”test1 called”的原因,我们找到了,但还有一点我比较疑惑的事情,任务T1,T2是在哪个线程里面执行的,在断点调试截图中我们看到,只有在执行任务T1时才创建了一个线程Thread6,执行T2时也是在Thread6中。
从调试截图中我们猜测只有用dispatch_async()函数分派block任务时会创建一个新的线程,而用dispatch_sync()函数分派block任务并不会创建线程,block执行时与dispatch_sync()函数处于同一个线程中。
说的比较绕,参考了下别人的说法,dispatch_sync所派发的block的执行线程和dispatch_sync上下文线程是同一个线程。
对于dispatch_sync中的block执行线程问题请参考:
http://zhangbuhuai.com/2015/04/11/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3dispatch_sync/