gpt4 book ai didi

ios - 嵌套 dispatch_sync/dispath_async 的进程死锁

转载 作者:行者123 更新时间:2023-11-29 10:35:17 25 4
gpt4 key购买 nike

我最近在玩 UIDocument 并且混淆了 dispatch_sync/dispath_async 的概念

我有一个获取所有文档信息的方法

for (int i=0; i < noteDocuments.count; i++) {            
NSURL * fileURL = [noteDocuments objectAtIndex:i];

NoteDocument *doc = [[NoteDocument alloc] initWithFileURL:fileURL];
[doc openWithCompletionHandler:^(BOOL success) {
[doc closeWithCompletionHandler:^(BOOL success) {
[self addOrUpdateInfoWithDoc:doc];
}];
}];
}

使用这种简单的方法一切正常。

然后我尝试 dispatch_sync/dispath_async

先用dispath_sync

dispatch_sync(dispatch_queue_create("test", DISPATCH_QUEUE_PRIORITY_DEFAULT), ^{
for (int i=0; i < noteDocuments.count; i++) {
NSURL * fileURL = [noteDocuments objectAtIndex:i];

NoteDocument *doc = [[NoteDocument alloc] initWithFileURL:fileURL];
[doc openWithCompletionHandler:^(BOOL success) {
[doc closeWithCompletionHandler:^(BOOL success) {
[self addOrUpdateInfoWithDoc:doc];
}];
}];
}
});

像这样添加 dispatch_sync 后,方法永远不会完成。这让我感到困惑,因为 dispath_sync 应该在 block 执行后返回到主队列,在这种情况下 openWithCompletionHandler 应该立即返回。

然后出于好奇,我将其更改为 dispatch_async(仅用于实验)

dispatch_async(dispatch_queue_create("test", DISPATCH_QUEUE_PRIORITY_DEFAULT), ^{
for (int i=0; i < noteDocuments.count; i++) {
NSURL * fileURL = [noteDocuments objectAtIndex:i];

NoteDocument *doc = [[NoteDocument alloc] initWithFileURL:fileURL];
[doc openWithCompletionHandler:^(BOOL success) {
[doc closeWithCompletionHandler:^(BOOL success) {
[self addOrUpdateInfoWithDoc:doc];
}];
}];
}
});

结果也让我感到困惑,我在 [doc openWithCompletionHandler:^(BOOL success) {

行上得到了 EXC_BAD_INSTRUCTION

谁能解释一下幕后发生的事情?这是我的理解,但显然是错误的。

This is what I understand, but it obviously wrong

最佳答案

我相信 NoteDocument 类派生自 UIDocument class .

<罢工>所以 -openWithCompletionHandler: completionHandler 在主队列上被调用。

-openWithCompletionHandler: Parameters: completionHandler

A block with code to execute after the open operation concludes.

The block is invoked on the main queue.

此外,我相信以下主队列(主线程)上的代码。

dispatch_sync(dispatch_queue_create("test", DISPATCH_QUEUE_PRIORITY_DEFAULT), ^{
...

这意味着您打算等待完成主队列中的队列。是的,它会阻塞主队列,直到队列结束。

openWithCompletionHandler:打开文档完成,然后提交completionHandler block 到主队列,但是主队列已经被dispatch_sync阻塞了。所以 completionHandler block 将永远不会被调用。因此,“测试”队列永远不会结束,dispatch_sync 也永远不会结束。

和 EXC_BAD_INSTRUCTION,我怀疑 -openWithCompletionHandler: 是否可以从其他线程调用。我不确定,但您可能需要从主线程调用该方法。

顺便说一下,您可能会误解 dispatch_queue_create 的第二个参数。

dispatch_queue_create("test", DISPATCH_QUEUE_PRIORITY_DEFAULT)

第二个参数是attr,它不是队列的优先级。

BSD Library Functions Manual dispatch_queue_create(3)

CREATION

The attr argument specifies the type of queue to create and must be either DISPATCH_QUEUE_SERIAL or DISPATCH_QUEUE_CONCURRENT.

幸运的是,在这种情况下这不是问题。在'''/usr/include/dispatch/queue.h'''

#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0

相同
#define DISPATCH_QUEUE_SERIAL NULL

编辑

如果 UIDocument -openWithCompletionHandler: 是普通方法,则不会导致 DEADLOCK。这将是以下顺序。

 main queue                 test queue
runloop
|
|
dispatch_sync [your block] ---->
(*BLOCKED*) [your block]
|
UIDocument -openWithCompletionHandler:
|
(opening document...)
|
(finished to open)
|
<------------------ dispatch_async [the completion block]
|
DONE
(Wake up from dispatch_sync
because test queue was finished)
|
|
the end of the runloop
execute blocks
|
[the completion block]
|
blocks done
|
|
go to the top of the runloop

但是,根据 LLDB 堆栈跟踪,它似乎与其他方法有点不同。

#0  0x0358dfb6 in semaphore_wait_trap ()
#1 0x032504bf in _dispatch_thread_semaphore_wait ()
#2 0x03249e4b in _dispatch_barrier_sync_f_slow ()
#3 0x0324ee3a in _dispatch_barrier_sync_f ()
#4 0x0324a728 in _dispatch_barrier_sync_slow ()
#5 0x0324a61c in dispatch_barrier_sync ()
#6 0x00a9044b in -[UIDocument(UIDocumentInternal) _performBlock:synchronouslyOnQueue:] ()
#7 0x00a9048d in -[UIDocument(UIDocumentInternal) _performBlockSynchronouslyOnMainThread:] ()
#8 0x00a866a3 in -[UIDocument _registerAsFilePresenterIfNecessary] ()
#9 0x00a87891 in -[UIDocument openWithCompletionHandler:] ()

所以顺序如下。

 main queue                 test queue
runloop
|
|
dispatch_sync [your block] ---->
(*BLOCKED*) [your block]
|
UIDocument -openWithCompletionHandler:
|
UIDocument _performBlockSynchronouslyOnMainThread:
|
<------------- dispatch_sync [UIDocument internal block]
(*BLOCKED*)

因此,死锁。

关于ios - 嵌套 dispatch_sync/dispath_async 的进程死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27477703/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com