是否在单线程上执行两次performBlockAndWait导致死锁?

时间:2016-02-23 12:26:21

标签: ios multithreading core-data

我在performBlockAndWait文档中找到了类似的内容:

  

可以安全地重新调用此方法。

我的问题是,这是否意味着它在以下情况下永远不会导致死锁会在单个上下文中调用它吗?:

NSManageObjectContext *context = ...

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

       [context performBlockAndWait:^{

       }];
 }];

1 个答案:

答案 0 :(得分:3)

您可以使用小代码片段自行尝试;)

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

我怀疑,内部实现使用特定于队列的令牌来识别代码执行的当前队列(请参阅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 
}

队列可能会像这样创建:

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)
}

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