Ios 如何在Grand Central Dispatch中创建死锁?
在苹果文档中,它说: 重要提示:您不应调用调度同步或调度同步 从与您在同一队列中执行的任务执行函数 计划移交给职能部门。这对我们来说尤其重要 串行队列,保证死锁,但也应 避免使用并发队列Ios 如何在Grand Central Dispatch中创建死锁?,ios,objective-c,xcode,grand-central-dispatch,Ios,Objective C,Xcode,Grand Central Dispatch,在苹果文档中,它说: 重要提示:您不应调用调度同步或调度同步 从与您在同一队列中执行的任务执行函数 计划移交给职能部门。这对我们来说尤其重要 串行队列,保证死锁,但也应 避免使用并发队列 如何编写代码来实现这一点?创建死锁的简单代码: dispatch_queue_t q = dispatch_queue_create("deadlock queue", DISPATCH_QUEUE_SERIAL); NSLog(@"1"); dispatch_async(q, ^{ NSLog(@"
如何编写代码来实现这一点?创建死锁的简单代码:
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_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\u sync
的调用者操作的队列不太明显的地方。这通常发生在一个(深度)嵌套堆栈中,在该堆栈中,您正在执行最初在某个队列上启动的某个类中的代码,并且意外地调用了一个dispatch\u sync
。阻止的最简单方法是在当前队列上执行dispatch\u 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
}
面试官经常问:“造成僵局的最简单方法是什么?”
Obj-C:
dispatch_sync(dispatch_get_main_queue(), ^{});
斯威夫特:
DispatchQueue.main.sync {}
从主线程调用
sync
将导致死锁,因为主队列是串行队列,sync
将停止当前队列执行,直到传递的块/闭包完成。在Swift 4.2中,可以使用以下代码段导致死锁:
let aSerialQueue = DispatchQueue(label: "my.label")
aSerialQueue.sync {
// The code inside this closure will be executed synchronously.
aSerialQueue.sync {
// The code inside this closure should also be executed synchronously and on the same queue that is still executing the outer closure ==> It will keep waiting for it to finish ==> it will never be executed ==> Deadlock.
}
}
如果有人好奇,那么如果针对同一队列调用了
sync
,则并发队列不会死锁。我知道这很明显,但我需要确认在我的例子中,只有串行队列的行为是这样的调度队列调用Xcode中的异常或设备上的崩溃,但是使用sleep()更适合我的测试目的(它只是当前队列中的冻结)
您想要创建死锁的代码示例吗?是的,有关学习,请参阅一个可以轻松死锁的实际示例。当处于死锁状态时。。。UI不应该是无响应的吗?@user1251004仅当主队列被阻止时才有效。在本例中,仅创建的
队列被阻止。主队列愉快地继续运行。是否有其他可能的方法在iOS中创建死锁?如果使用并发队列,会发生什么情况?非常感谢@Joriskluivers为什么内部块要等到外部块完成后才启动?@ScottyBlades,因为这是一个串行队列OK。知道了。异步块被添加到队列中,并在尝试执行时,它将命中同步函数,该函数在异步块完成执行之前不会启动,这是永远不会发生的,因为块需要到达其执行的结尾,而这是永远不会发生的,因为queue.sync正在等待另一个。这将在第3行给出EXC_BAD_指令
sleep(UInt32.max)