我有一个自定义的串行队列,在这个同步调用主队列的旁边。这造成了僵局。根据我的理解,两者都是独立的队列,所以它应该工作,并且两者(步骤3和步骤5(都应该执行同步块。有人能解释为什么会出现死锁吗?下面是我的操场代码。
func serialQueueTest() {
let customSerialQueue = DispatchQueue(label: "com.test.dipak")
print("Step 1")
customSerialQueue.async {
print("Step 2")
DispatchQueue.main.sync {
print("Step 3: Inside main sync queue")
}
}
print("Step 4")
customSerialQueue.sync {
print("Step 5: Inside Custom Serial Queue sync queue")
}
}
您正在阻塞main。
在从main调用的步骤4中,main将块提交到队列并等待它完成。但到那时,您已经提交了第一个块(步骤1(,它又在等待main释放。
编辑
请注意,CSQ并不是阻止尝试执行您提交的两个块,而是阻止CSQ和main等待彼此完成。如果队列上有isBusy
函数,我可以很容易地说明这一点,但由于没有,让我们假设有,并查看下面的代码。
func serialQueueTest() {
let customSerialQueue = DispatchQueue(label: "com.test.dipak")
print("Step 1")
customSerialQueue.async {
print("Step 2")
// Previously
// DispatchQueue.main.sync { AAA }
// same as below pseudo code
while ( main.isBusy )
{
wait ... *without* releasing control
}
now, on main, do AAA and then proceed
print ( "****" )
print ( "CSQ will now wait for main to finish what it is doing ..." )
print ( "But note, it does not release control or do something else," )
print ( "it *blocks* until main is finished. So it deadlocks." )
}
print("Step 4")
// Previously
// customSerialQueue.sync BBB
// replaced with ...
while ( csq.isBusy )
{
wait ... *without* releasing control
}
now, on csq, do BBB then proceed
print ( "****" )
print ( "Main will now wait for csq to finish what it is doing ..." )
print ( "But note, it does not release control or do something else," )
print ( "it *blocks* until csq is finished. So it deadlocks." )
}
这也会阻止,即使我只向CSQ提交了一个块。
为了打破死锁,你可以在等待释放控制时(在这种情况下,你可以调用async而不是sync(,或者使用不同类型的锁,或者以不同的方式等待另一个锁完成。
编辑2
让我把它简化为本质。
// This runs on main
// This runs on csq
csq.async { main.sync // csq now waits on main to free up }
csq.sync // main now waits on csq to free up
// and you have deadlock
为了进一步了解Tushar Sharma和Dipak的答案,我将按照代码执行的顺序一步一步地浏览代码。
// == Scheduling a work item from the main queue ==
// Create a new serial queue
let customSerialQueue = DispatchQueue(label: "com.test.dipak")
// Create a work item and append it to customSerialQueue.
// Don't think of this being "in parallel." These are not threads. They're
// queues. It will run the next time customSerialQueue is scheduled. That might
// be immediately (if there's an available core), and that might be in the
// arbitrarily distant future. It doesn't matter what's in this work item. It's
// just "some work to do."
customSerialQueue.async { ... }
// On main queue still
print("Step 4")
// Create a work item, append it to customSerialQueue, and wait for it to
// complete. As before, it doesn't matter what's in this work item. It's just
// stuck onto the end of customSerialQueue and will execute when it gets to the
// front of the queue and the queue is scheduled. Currently it's 2nd in line
// after the Step 2 work item.
customSerialQueue.sync { ... }
此时,main必须屈服(块(。它无法继续并完成当前工作项(运行serialQueueTest的工作项(,直到步骤5工作项完成。
由于现在什么都没有运行,所以customSerialQueue上的第一个块可以运行。
// == Scheduling a work item from customSerialQueue ==
print("Step 2")
// Create a block, append it the main queue, and wait for it to complete.
DispatchQueue.main.sync { ... }
和以前一样,customSerialQueue必须产生(块(。在第3步工作项完成之前,它无法继续并完成当前工作项(运行第2步的工作项(。在main完成当前正在运行的工作项之前,无法调度步骤3工作项(main是一个串行队列(。
此时,main被阻塞,等待";步骤5";块以完成,并且customSerialQueue被阻止等待";步骤3";完成。这是一个典型的死锁,两项任务都无法进行。
在存在多个核心的情况下,上述各项均未发生变化。GCD队列是关于并发性的,而不是并行性(并且并发性不是并行性(。它们不是关于事物运行的"同时"它们是关于安排工作项目的。所以你应该首先把它们当作在一个核心上运行。然后,您可以添加两个工作项同时运行时会发生什么的问题。但这个问题并不能改变依赖关系的基本问题。