xcode 如何在 Grand Central Dispatch 中制造僵局?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15381209/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I create a deadlock in Grand Central Dispatch?
提问by BlackMouse
In Apple docs, it says:
在 Apple 文档中,它说:
Important:?You should never call the dispatch_sync or dispatch_sync_f function from a task that is executing in the same queue that you are planning to pass to the function. This is particularly important for serial queues, which are guaranteed to deadlock, but should also be avoided for concurrent queues.
重要提示:?您永远不应该从在您计划传递给函数的同一队列中执行的任务调用 dispatch_sync 或 dispatch_sync_f 函数。这对于保证死锁的串行队列尤其重要,但对于并发队列也应避免。
How do you write the code to do exactly this?
你如何编写代码来做到这一点?
回答by Joris Kluivers
An intentional deadlock on a certain queue:
某个队列上的故意死锁:
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
});
It's clear here that the outer and inner blocks are operating on the same queue. Most cases where this will occur is in places where it's less obvious what queue the caller of the dispatch_sync
is operating on. This usually occurs in a (deeply) nested stack where you're executing code in some class that was originally launched on a certain queue, and by accident you call a dispatch_sync
to the same queue.
很明显,外部块和内部块在同一个队列上运行。大多数情况下,会发生这种情况的地方不太明显,调用者dispatch_sync
正在操作的队列中。这通常发生在(深层)嵌套堆栈中,您在其中执行最初在某个队列上启动的某个类中的代码,并且意外地将 a 调用dispatch_sync
到同一队列。
回答by Vladimir
Simple code that creates deadlock:
创建死锁的简单代码:
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");
Log output:
日志输出:
1
5
2
Here internal block is scheduled to be run on serial queue q
but it cannot run until current block is finished, while current block, in turn, waits internal to finish as we called it synchronously.
这里内部块被安排在串行队列上运行,q
但在当前块完成之前它不能运行,而当前块反过来等待内部完成,我们称之为同步。
回答by Nikolai Ruhe
The simplest way to block is to dispatch_sync
on the current queue:
阻塞的最简单方法是dispatch_sync
在当前队列上:
dispatch_sync(dispatch_get_current_queue(), ^{});
This blocks when the current queue is a serial queue, for example the main queue.
当当前队列是串行队列(例如主队列)时,这会阻塞。
回答by Bart?omiej Semańczyk
In latest Swift syntax:
在最新的 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
}
回答by Bohdan Orlov
Interviewers often ask: "What is the simplest way to cause a deadlock?"
面试官经常问:“导致僵局的最简单方法是什么?”
Obj-C:
对象-C:
dispatch_sync(dispatch_get_main_queue(), ^{});
Swift:
迅速:
DispatchQueue.main.sync {}
Calling sync
from the main thread will cause a deadlock because the main queue is a serial queue and sync
stops current queue execution until passed block/closure has finished.
sync
从主线程调用会导致死锁,因为主队列是一个串行队列并sync
停止当前队列的执行,直到传递的块/闭包完成。
回答by Moe
In Swift 4.2 you can cause a deadlock using the following piece of code:
在 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.
}
}
回答by Alexandru Motoc
If anyone is curious, a concurrent queue does NOT deadlock if sync
is called targeting the same queue. I know it's obvious but I needed to confirm only serial queues behave that way
如果有人好奇,如果sync
针对同一队列调用并发队列,则并发队列不会死锁。我知道这很明显,但我只需要确认串行队列的行为方式
Works:
作品:
let q = DispatchQueue(label: "myQueue", attributes: .concurrent)
q.async {
print("work async start")
q.sync {
print("work sync in async")
}
print("work async end")
}
q.sync {
print("work sync")
}
print("done")
Fails:
失败:
Initialize q
as let q = DispatchQueue(label: "myQueue") // implicitly serial queue
初始化q
为let q = DispatchQueue(label: "myQueue") // implicitly serial queue