单线程调用两次performBlockAndWait是否会导致死锁?

Rob*_*ert 3 multithreading core-data ios

我在文档中发现了类似的内容performBlockAndWait

可以安全地以可重入的方式调用此方法。

我的问题是,这是否意味着当我在单个上下文中像这样调用它时,它永远不会导致死锁?:

NSManageObjectContext *context = ...

[context performBlockAndWait:^{
       // ... some stuff

       [context performBlockAndWait:^{

       }];
 }];
Run Code Online (Sandbox Code Playgroud)

Cou*_*per 5

您可以使用一小段代码自己尝试一下;)

但事实是,它不会陷入僵局。

我怀疑,内部实现使用队列特定令牌来识别代码执行的当前队列(请参阅dispatch_queue_set_specificdispatch_queue_get_specific)。

如果它确定当前正在执行的代码在其自己的私有队列或子队列上执行,它会简单地绕过同步提交块(这会导致死锁),而是直接执行它。

我的一个可能的实现如下:

func executeSyncSafe(f: () -> ()) {
    if isSynchronized() {
        f()
    } else {
        dispatch_sync(syncQueue, f)
    }
}

func isSynchronized() -> Bool {
    let context = UnsafeMutablePointer<Void>(Unmanaged<dispatch_queue_t>.passUnretained(syncQueue).toOpaque())
    return dispatch_get_specific(&queueIDKey) == context 
}
Run Code Online (Sandbox Code Playgroud)

队列可能是这样创建的:

private var queueIDKey = 0  // global


init() {
    dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL,
            QOS_CLASS_USER_INTERACTIVE, 0))
    let context = UnsafeMutablePointer<Void>(Unmanaged<dispatch_queue_t>.passUnretained(syncQueue).toOpaque())
    dispatch_queue_set_specific(syncQueue, &queueIDKey, context, nil)
}
Run Code Online (Sandbox Code Playgroud)

dispatch_queue_set_specific令牌(此处context只是队列的指针值)与该队列的某个键相关联。之后,您可以尝试为指定的任何队列检索该令牌,并检查当前队列是同一个队列还是子队列。如果这是真的,则绕过调度到队列,而是f直接调用该函数。