为什么两个不同的串行队列会在 swift 中造成死锁?

Dee*_*pak 3 objective-c grand-central-dispatch swift dispatch-queue

我有一个自定义串行队列,在该队列中同步调用主队列。这正在造成僵局。根据我的理解,两者都是独立的队列,因此它应该可以工作,并且两个(步骤 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")
    }
}
Run Code Online (Sandbox Code Playgroud)

ska*_*aak 5

你正在阻止 main.

在第 4 步(从 main 调用)中,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." )
    }

Run Code Online (Sandbox Code Playgroud)

即使我只向 CSQ 提交了一个区块,这也会被阻止。

要打破死锁,您可以在等待释放控制时(在这种情况下,您可以调用异步而不是同步)或使用不同类型的锁或以不同的方式等待另一个锁完成。

编辑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
Run Code Online (Sandbox Code Playgroud)