如何在Grand Central Dispatch中创建死锁?

时间:2013-03-13 09:21:28

标签: ios objective-c xcode grand-central-dispatch

在Apple文档中,它说:

  

重要提示:您永远不应该调用dispatch_sync或dispatch_sync_f   从您在同一队列中执行的任务中运行   计划传递给函数。这对于特别重要   串行队列,保证死锁,但也应该是   避免并发队列。

你如何编写代码才能做到这一点?

8 个答案:

答案 0 :(得分:30)

某个队列上的故意死锁:

dispatch_queue_t queue = dispatch_queue_create("my.label", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
    dispatch_sync(queue, ^{
        // outer block is waiting for this inner block to complete,
        // inner block won't start before outer block finishes
        // => deadlock
    });

    // this will never be reached
}); 

这里很明显外部和内部块在同一队列上运行。发生这种情况的大多数情况是在dispatch_sync的调用者正在操作的队列不太明显的地方。这通常发生在(深度)嵌套堆栈中,您在某个类中执行最初在某个队列上启动的代码,并且偶然地将dispatch_sync调用到同一队列。

答案 1 :(得分:13)

创建死锁的简单代码:

dispatch_queue_t q = dispatch_queue_create("deadlock queue", DISPATCH_QUEUE_SERIAL);

NSLog(@"1");
dispatch_async(q, ^{
    NSLog(@"2");
    dispatch_sync(q, ^{
        NSLog(@"3");
    });
    NSLog(@"4");
});
NSLog(@"5");

日志输出:

1
5
2

此处内部块计划在串行队列q上运行,但是在当前块完成之前它不能运行,而当前块在内部完成,因为我们同步调用它。

答案 2 :(得分:7)

最简单的阻止方法是在当前队列上dispatch_sync

dispatch_sync(dispatch_get_current_queue(), ^{});

当当前队列是串行队列时阻塞,例如主队列。

答案 3 :(得分:4)

In latest Swift syntax:

self.navigationController?.navigationBar.setValue(true, forKey: "hidesShadow")

答案 4 :(得分:1)

采访者经常会问:“造成僵局的最简单方法是什么?”

的OBJ-C:

dispatch_sync(dispatch_get_main_queue(), ^{});

夫特:

DispatchQueue.main.sync {}

从主线程调用sync将导致死锁,因为主队列是一个串行队列,sync停止当前队列执行,直到传递阻塞/闭包完成。

答案 5 :(得分:1)

如果有人感到好奇,并且如果调用sync以同一队列为目标,则并发队列不会死锁。我知道这很明显,但是我需要确认只有串行队列的行为如此

作品:

let q = DispatchQueue(label: "myQueue", attributes: .concurrent)

q.async {
    print("work async start")
    q.sync {
        print("work sync in async")
    }
    print("work async end")
}

q.sync {
    print("work sync")
}

print("done")

失败:

q初始化为let q = DispatchQueue(label: "myQueue") // implicitly serial queue

答案 6 :(得分:0)

在Swift 4.2中,您可以使用以下代码导致死锁:

let aSerialQueue = DispatchQueue(label: "my.label")

aSerialQueue.sync {
    // The code inside this closure will be executed synchronously.
    aSerialQueue.sync {
        // The code inside this closure should also be executed synchronously and on the same queue that is still executing the outer closure ==> It will keep waiting for it to finish ==> it will never be executed ==> Deadlock.
    }
}

答案 7 :(得分:0)

在我的情况下,调度队列在Xcode中调用异常或在设备上崩溃,但是 sleep()的使用更适合我的测试目的(只是冻结)当前队列)。

const [cont, setCont] = useState([]);