xcode 如何在 Grand Central Dispatch 中制造僵局?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15381209/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 02:57:43  来源:igfitidea点击:

How do I create a deadlock in Grand Central Dispatch?

iosobjective-cxcodegrand-central-dispatch

提问by BlackMouse

In Apple docs, it says:

在 Apple 文档中,它说:

Important:?You should never call the dispatch_sync or dispatch_sync_f function from a task that is executing in the same queue that you are planning to pass to the function. This is particularly important for serial queues, which are guaranteed to deadlock, but should also be avoided for concurrent queues.

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

How do you write the code to do exactly this?

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

回答by Joris Kluivers

An intentional deadlock on a certain queue:

某个队列上的故意死锁:

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

It's clear here that the outer and inner blocks are operating on the same queue. Most cases where this will occur is in places where it's less obvious what queue the caller of the dispatch_syncis operating on. This usually occurs in a (deeply) nested stack where you're executing code in some class that was originally launched on a certain queue, and by accident you call a dispatch_syncto the same queue.

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

回答by Vladimir

Simple code that creates deadlock:

创建死锁的简单代码:

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");

Log output:

日志输出:

1
5
2

Here internal block is scheduled to be run on serial queue qbut it cannot run until current block is finished, while current block, in turn, waits internal to finish as we called it synchronously.

这里内部块被安排在串行队列上运行,q但在当前块完成之前它不能运行,而当前块反过来等待内部完成,我们称之为同步。

回答by Nikolai Ruhe

The simplest way to block is to dispatch_syncon the current queue:

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

dispatch_sync(dispatch_get_current_queue(), ^{});

This blocks when the current queue is a serial queue, for example the main queue.

当当前队列是串行队列(例如主队列)时,这会阻塞。

回答by Bart?omiej Semańczyk

In latest Swift syntax:

在最新的 Swift 语法中:

let queue = DispatchQueue(label: "label")
queue.async {
    queue.sync {
        // 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
}

回答by Bohdan Orlov

Interviewers often ask: "What is the simplest way to cause a deadlock?"

面试官经常问:“导致僵局的最简单方法是什么?”

Obj-C:

对象-C:

dispatch_sync(dispatch_get_main_queue(), ^{});

Swift:

迅速:

DispatchQueue.main.sync {}

Calling syncfrom the main thread will cause a deadlock because the main queue is a serial queue and syncstops current queue execution until passed block/closure has finished.

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

回答by Moe

In Swift 4.2 you can cause a deadlock using the following piece of code:

在 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.
    }
}

回答by Alexandru Motoc

If anyone is curious, a concurrent queue does NOT deadlock if syncis called targeting the same queue. I know it's obvious but I needed to confirm only serial queues behave that way

如果有人好奇,如果sync针对同一队列调用并发队列,则并发队列不会死锁。我知道这很明显,但我只需要确认串行队列的行为方式

Works:

作品:

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

Fails:

失败:

Initialize qas let q = DispatchQueue(label: "myQueue") // implicitly serial queue

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