如何在Grand Central Dispatch中创build一个死锁?
在苹果文档中,它说:
重要提示:您不应该从正在计划传递给该函数的同一队列中执行的任务调用dispatch_sync或dispatch_sync_f函数。 这对保证死锁的串行队列尤为重要,但对于并发队列也应该避免。
你如何编写代码来做到这一点?
某个队列上的故意死锁:
dispatch_queue_t queue = dispatch_queue_create("my.label", DISPATCH_QUEUE_SERIAL); dispatch_async(queue, ^{ dispatch_sync(queue, ^{ // outer block is waiting for this inner block to complete, // inner block won't start before outer block finishes // => deadlock }); // this will never be reached });
这里很清楚,外部和内部块在同一队列上运行。 这种情况发生的大多数情况是dispatch_sync
的调用者在哪个队列中运行的地方。 这通常发生在一个(深)嵌套堆栈中,在这个堆栈中,您正在某个队列中初始启动的某个类中执行代码,并且偶然会将dispatch_sync
调用到同一个队列中。
造成死锁的简单代码:
dispatch_queue_t q = dispatch_queue_create("deadlock queue", DISPATCH_QUEUE_SERIAL); NSLog(@"1"); dispatch_async(q, ^{ NSLog(@"2"); dispatch_sync(q, ^{ NSLog(@"3"); }); NSLog(@"4"); }); NSLog(@"5");
日志输出:
1 5 2
这里内部块预定在串行队列q
上运行,但是直到当前块结束才能运行,而当前块又等待内部完成,因为我们同步调用它。
最简单的方法是在当前队列中dispatch_sync
同步:
dispatch_sync(dispatch_get_current_queue(), ^{});
当当前队列是一个串行队列,例如主队列时,这会阻塞。
在最新的Swift语法中:
let queue = DispatchQueue(label: "label") queue.async { queue.sync { // outer block is waiting for this inner block to complete, // inner block won't start before outer block finishes // => deadlock } // this will never be reached }