dispatch_semaphore_dispose 上的 EXC_BAD_INSTRUCTION(代码=EXC_I386_INVOP,子代码=0x0)

Posted

技术标签:

【中文标题】dispatch_semaphore_dispose 上的 EXC_BAD_INSTRUCTION(代码=EXC_I386_INVOP,子代码=0x0)【英文标题】:EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) on dispatch_semaphore_dispose 【发布时间】:2014-08-11 19:59:02 【问题描述】:

我在 dispatch_semaphore_dispose 上收到 EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) 但我真的不知道如何追查其根本原因。我的代码使用了 dispatch_async、dispatch_group_enter 等等。

更新: 崩溃的原因是由于 webserviceCall(见下面的代码)从不调用 onCompletion 并且当代码再次运行时,我收到错误 EXC_BAD_INSTRUCTION。我证实确实如此,但不知道为什么或如何防止这种情况。

代码:

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_group_t group = dispatch_group_create();

     for (...) 
        if (...) 
            dispatch_group_enter(group);
            dispatch_async(queue, ^

               [self webserviceCall:url onCompletion:^
                     dispatch_group_leave(group);
               ];
            );
        
    

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
    dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)));
    dispatch_sync(queue, ^
        // call completion handler passed in by caller
    );
);

【问题讨论】:

不是重复的。我看了看,对我没有帮助。注意我的也是 EXC_I386_INVOP。 这可能是 ARC 问题。发布您对调度组、信号量或 dispatch_sync 所做的任何事情。 ARC 可能正在尝试处理已设置为 NULL 的信号量。 为了在块内使用weakSelf。 FYI 1. 如果您创建了一个由您自己编写的fatalError/assertionFailure,您将收到一个错误EXC_BAD_INSTRUCTION。因此你应该明白为什么你已经达到了你自己的断言,即查看它的信息。话虽如此,这个错误是由编译器产生的。 2. 我的观点是编译器也使用fatalError,我们看到的许多错误都是因为这个 【参考方案1】:

从您的堆栈跟踪中,EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) 发生是因为 dispatch_group_t 在仍处于锁定状态(等待 dispatch_group_leave)时被释放

根据你的发现,事情是这样的:

dispatch_group_t group 已创建。 group 的保留计数 = 1。 -[self webservice:onCompletion:] 捕获了groupgroup 的保留计数 = 2。 dispatch_async(...., ^ dispatch_group_wait(group, ...) ... ); 再次捕获了groupgroup 的保留计数 = 3。 退出当前范围。 group 已发布。 group 的保留计数 = 2。 dispatch_group_leave 从未被调用过。 dispatch_group_wait 超时。 dispatch_async 块已完成。 group 已发布。 group 的保留计数 = 1。 您再次调用了此方法。当再次调用-[self webservice:onCompletion:] 时,旧的onCompletion 块被替换为新的块。所以,旧的group 被释放了。 group 的保留计数 = 0。 group 已被释放。结果是EXC_BAD_INSTRUCTION

要解决这个问题,我建议你应该找出-[self webservice:onCompletion:] 没有调用onCompletion 阻止的原因,并修复它。然后确保对方法的下一次调用将在上一次调用完成之后发生。


如果您允许该方法被多次调用,无论之前的调用是否完成,您可能会找人为您保留group

您可以将超时时间从 2 秒更改为 DISPATCH_TIME_FOREVER 或所有 -[self webservice:onCompletion] 应该调用其 onCompletion 块的合理时间量。这样dispatch_async(...) 中的块就会为您保存它。 或者 您可以将group 添加到集合中,例如NSMutableArray

我认为这是为此操作创建专用类的最佳方法。当你想调用 webservice 时,你创建一个类的对象,调用它的方法,完成块传递给它,释放对象。在类中,有一个dispatch_group_tdispatch_semaphore_t 的ivar。

【讨论】:

哇,惊人的分析。如果我将组添加到集合中,它永远不会被释放,对吧?我可能无法修复不返回的 web 服务,因为这是一个框架,我不能阻止其他人创建不返回的 web 服务调用(错误地),我想确保我的框架不会崩溃那些情况。 是的,所以你必须在使用完后将其从集合中移除。 这个答案对我帮助很大。非常感谢!就我而言,我只在 onCompletion 中调用了 dispatch_group_leave,但在 onCancellation 中忘记了调用它。在任何情况下调用 dispatch_group_leave 都可以解决我的问题。 帮了我大忙,我宣布了一个ivar调度组,但没有进出比较。 对我来说这很奇怪,我有 2 个参数错误地具有相同的名称,并且在运行时出现此错误。【参考方案2】:

我的问题是我正在创建想要存储在 NSMutableDictionary 中的对象,但我从未初始化字典。因此,对象被垃圾收集删除并在以后破坏。检查您是否对正在与之交互的对象至少有一个强引用。

【讨论】:

【参考方案3】:

就我而言:

PHImageRequestOptions *requestOptions = [PHImageRequestOptions new];
requestOptions.synchronous            = NO;

试图用 dispatch_group 来做这个

【讨论】:

【参考方案4】:

我的问题是IBOutlet,但没有连接到界面生成器并在 swift 文件中使用。

【讨论】:

我也有同样的问题。我们能否从错误消息中找出哪些 IBOutlet 可以取消链接? 如果该类只有一个 1 InterfaceBuilder,那么您可以检查 .swift 或 .m / .h 文件中的每个 IBOutlet 连接或断开符号。 有同样的问题,是从一个按钮引用一个动作而不将按钮本身添加为 IBOutlet。【参考方案5】:

我有一个不同的问题让我想到了这个问题,这可能比已接受答案中的过度发布问题更常见。

根本原因是我们的完成块被调用两次,因为网络处理程序中的 if/else 失败,导致每次调用 dispatch_group_enter 都会调用两次 dispatch_group_leave。 p>

完成块被多次调用:

dispatch_group_enter(group);
[self badMethodThatCallsMULTIPLECompletions:^(NSString *completion) 

    // this block is called multiple times
    // one `enter` but multiple `leave`

    dispatch_group_leave(group);
];

通过 dispatch_group 的 count 调试

EXC_BAD_INSTRUCTION 上,您应该仍然可以在调试器中访问您的 dispatch_group。 DispatchGroup: check how many "entered"

打印出 dispatch_group 你会看到:

<OS_dispatch_group: group[0x60800008bf40] = xrefcnt = 0x2, refcnt = 0x1, port = 0x0, count = -1, waiters = 0 >

当您看到count = -1 时,表明您已经过度离开了 dispatch_group。请务必将dispatch_enterdispatch_leave 分组配对。

【讨论】:

关于count = -1 的提示非常有帮助 - 谢谢! 我遇到了类似的情况-尽管在完成块中使用了 group=DispatchGroup() 和 group.enter() 以及相应的 group.leave() (被多次调用)。在调试器中,组的计数是 1073741823——作为有符号的 32 位 int 也是 -1【参考方案6】:

我来到这里是因为一个 XCTestCase,我在其中禁用了大多数测试,方法是在 no_testBackgroundAdding 中添加“no_”作为前缀。一旦我注意到大多数答案都与锁和线程有关,我意识到测试包含一些 XCTestExpectation 实例和相应的 waitForExpectations。它们都在禁用测试中,但显然 Xcode 仍在某种程度上评估它们。

最后我找到了一个定义为@property 但缺少@synthesize 的XCTestExpectation。一旦我添加了综合指令,EXC_BAD_INSTRUCTION 就消失了。

【讨论】:

【参考方案7】:

有时获得EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) 所需要的只是缺少return 语句。

这当然是我的情况。

【讨论】:

【参考方案8】:

我的问题是它在我的 init() 中。 可能是“弱自我”在初始化尚未完成时杀死了他。 我将它从 init 中移出,它解决了我的问题。

【讨论】:

以上是关于dispatch_semaphore_dispose 上的 EXC_BAD_INSTRUCTION(代码=EXC_I386_INVOP,子代码=0x0)的主要内容,如果未能解决你的问题,请参考以下文章