首页 > 解决方案 > 使用 GCD,DispatchGroup 如何在组离开之前(或之后)从后台队列在主队列上运行项目,而不会出现死锁?

问题描述

给定某个Foo在后台线程上调用 Bar 以执行某些工作的类,如何Bar在封闭函数返回它需要返回的值之前设置一些工作在主线程上完成而不会导致死锁?

例如,“asdf”如何在“done”打印之前打印,beforetruefunc done() -> Bool下面的示例中返回?

import Dispatch

class Foo {
   /// always called from the main queue
   func done() -> Bool {
       let group = DispatchGroup()
       group.enter()
       DispatchQueue.global().async {
           Bar().perform {
               DispatchQueue.main.async { print("asdf") } 
                    // "asdf" prints after "done" is printed
               group.leave()
           }
       }
       group.wait()
       print("done")
       return true
    }
}

哪里Bar很简单:

struct Bar {
    func perform(_ work: @escaping () -> Void) { work() }
}

我需要 Bar 能够设置一些应该在done()返回之前在主队列上执行的工作,而不会导致死锁(如果我们将上面的perform块更改为使用DispatchQueue.main.sync,并且(假设done()总是在主线程上调用,这是)。

在我们打印“完成”之前,我能想出的打印“asdf”的唯一解决方案是更改done()函数如下:

    func done() -> Bool {
        let group1 = DispatchGroup()
        var completion: (() -> Void)? = nil
        group1.enter()
        DispatchQueue.global().async(group: group1) {
            Bar().perform {
                completion = { print("asdf") }
                group1.leave()
            }
        }
        group1.wait()
        completion?()
        print("done")
        return true
    }

这里的completion块在函数返回之前在主线程上运行。然而,这感觉很笨拙和笨拙……似乎 GCD 应该为我们处理。但是我尝试过的所有其他操作都将在函数返回后运行。

想法?

标签: swiftconcurrencygrand-central-dispatch

解决方案


GCD 下的主队列是不可重入的,done除非阻塞主线程,否则不能立即停止返回,也不能(因此)done在第一个异步方法之后返回值。

因此,正如您在评论中被告知的那样,您尝试做的事情是不可能的。

您可以通过(例如)另一个完成处理程序从 Bar 完成处理程序内部回调主线程;但你不能像你试图做的那样“等待”。

例如:

struct Bar {
    func perform(_ work: @escaping () -> Void) {
        print("work")
        work()
    }
}
class Foo {
    func done(_ f: @escaping (Bool) -> ()) {
       DispatchQueue.global().async {
           Bar().perform {
               DispatchQueue.main.async {
                    // adjust the order of these two lines as desired
                    print("asdf")
                    f(true)
               }
           }
       }
    }
}
let f = Foo()
f.done { what in
    print(what)
    print("done")
}

输出:

work
asdf
true
done

推荐阅读