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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24337791/
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-08-31 01:01:45  来源:igfitidea点击:

EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) on dispatch_semaphore_dispose

iosobjective-cexceptiongrand-central-dispatch

提问by Boon

I am getting EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) on dispatch_semaphore_dispose but don't really know how to track down the root cause of this. My code makes use of dispatch_async, dispatch_group_enter and so on.

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

UPDATE: The cause of the crash is due to the fact that the webserviceCall (see code below) never calls onCompletion and when the code is run again, I got the error EXC_BAD_INSTRUCTION. I verified this is indeed the case, but not sure why or how to prevent this.

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

enter image description here

在此处输入图片说明

Code:

代码:

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

回答by 3329

From your stack trace, EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)occurred because dispatch_group_twas released while it was still locking (waiting for dispatch_group_leave).

从您的堆栈跟踪中,EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)发生的原因dispatch_group_t是在仍在锁定 (waiting for dispatch_group_leave) 时被释放

According to what you found, this was what happened :

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

  • dispatch_group_t groupwas created. group's retain count = 1.
  • -[self webservice:onCompletion:]captured the group. group's retain count = 2.
  • dispatch_async(...., ^{ dispatch_group_wait(group, ...) ... });captured the groupagain. group's retain count = 3.
  • Exit the current scope. groupwas released. group's retain count = 2.
  • dispatch_group_leavewas never called.
  • dispatch_group_waitwas timeout. The dispatch_asyncblock was completed. groupwas released. group's retain count = 1.
  • You called this method again. When -[self webservice:onCompletion:]was called again, the old onCompletionblock was replaced with the new one. So, the old groupwas released. group's retain count = 0.groupwas deallocated. That resulted to EXC_BAD_INSTRUCTION.
  • dispatch_group_t group被创建。group的保留计数 = 1。
  • -[self webservice:onCompletion:]捕获了group. group的保留计数 = 2。
  • dispatch_async(...., ^{ dispatch_group_wait(group, ...) ... });group再次捕获。group的保留计数 = 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.

To fix this, I suggest you should find out why -[self webservice:onCompletion:]didn't call onCompletionblock, and fix it. Then make sure the next call to the method will happen after the previous call did finish.

为了解决这个问题,我建议你找出为什么-[self webservice:onCompletion:]不调用onCompletionblock 并修复它。然后确保该方法的下一次调用将在上一次调用完成后发生。



In case you allow the method to be called many times whether the previous calls did finish or not, you might find someone to hold groupfor you :

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

  • You can change the timeout from 2 seconds to DISPATCH_TIME_FOREVERor a reasonable amount of time that all -[self webservice:onCompletion]should call their onCompletionblocks by the time. So that the block in dispatch_async(...)will hold it for you.
    OR
  • You can add groupinto a collection, such as NSMutableArray.
  • 您可以将超时从 2 秒更改为DISPATCH_TIME_FOREVER所有人都-[self webservice:onCompletion]应该按时调用其onCompletion块的合理时间。这样里面的块dispatch_async(...)就会为你保存它。
    或者
  • 您可以添加group到集合中,例如NSMutableArray.


I think it is the best approach to create a dedicate class for this action. When you want to make calls to webservice, you then create an object of the class, call the method on it with the completion block passing to it that will release the object. In the class, there is an ivar of dispatch_group_tor dispatch_semaphore_t.

我认为这是为此操作创建专用类的最佳方法。当您想要调用webservice 时,您然后创建该类的一个对象,调用它的方法并传递给它的完成块将释放该对象。在类中,有一个dispatch_group_tor的 ivar dispatch_semaphore_t

回答by Mrugesh Tank

My problem was took IBOutletbut didn't connect with interface builder and using in swift file.

我的问题被解决了,IBOutlet但没有与界面构建器连接并在 swift 文件中使用。

回答by pkamb

I had a different issue that brought me to this question, which will probably be more common than the overrelease issue in the accepted answer.

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

Root cause was our completion block being called twicedue to bad if/else fallthrough in the network handler, leading to two calls of dispatch_group_leavefor every one call to dispatch_group_enter.

根本原因是我们的完成块由于网络处理程序中的 if/else 失败而被调用两次,导致dispatch_group_leave每次调用dispatch_group_enter.

Completion block called multiple times:

多次调用完成块:

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

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

    dispatch_group_leave(group);
}];

Debug via the dispatch_group's count

通过 dispatch_group 的调试 count

Upon the EXC_BAD_INSTRUCTION, you should still have access to your dispatch_group in the debugger. Print out the dispatch_group and you'll see:

在 上EXC_BAD_INSTRUCTION,您应该仍然可以在调试器中访问您的 dispatch_group。打印出 dispatch_group ,你会看到:

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

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

When you see count = -1it indicates that you've over-left the dispatch_group. Be sure to dispatch_enterand dispatch_leavethe group in matched pairs.

当您看到count = -1它时,表明您已经超出了 dispatch_group 的范围。一定要dispatch_enterdispatch_leave组配对。

回答by mihai

My issue was that I was creating objects that I wanted to be stored in a NSMutableDictionary but I never initialized the dictionary. Therefore the objects were getting deleted by garbage collection and breaking later. Check that you have at least one strong reference to the objects youre interacting with.

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

回答by Gabriel

Sometimes all it takes to get a EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)is a missing returnstatement.

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

It certainly was my case.

这当然是我的情况。

回答by Zaporozhchenko Oleksandr

In my case:

就我而言:

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

Was trying to do this with dispatch_group

试图用 dispatch_group 做到这一点

回答by Elise van Looij

I landed here because of an XCTestCase, in which I'd disabled most of the tests by prefixing them with 'no_' as in no_testBackgroundAdding. Once I noticed that most of the answers had something to do with locks and threading, I realized the test contained a few instances of XCTestExpectation with corresponding waitForExpectations. They were all in the disabled tests, but apparently Xcode was still evaluating them at some level.

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

In the end I found an XCTestExpectation that was defined as @property but lacked the @synthesize. Once I added the synthesize directive, the EXC_BAD_INSTRUCTION disappeared.

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

回答by Yaron Abramovich

My issue was that it was in my init(). Probably the "weak self" killed him while the init wasn't finished. I moved it from the init and it solved my issue.

我的问题是它在我的 init() 中。可能是“弱小的自我”在 init 还没有完成的时候杀了他。我将它从 init 中移出,它解决了我的问题。