为什么这个dispatch_sync()调用冻结?

teu*_*nks 29 multithreading cocoa-touch objective-c grand-central-dispatch

我正在使用Kiwi测试框架在我的应用程序中测试身份验证方法.在调用dispatch_sync时,测试冻结,如下所示:

dispatch_queue_t main = dispatch_get_main_queue();
dispatch_sync(main, ^
                  {
                      [[NSNotificationCenter defaultCenter] postNotificationName:kNotificationAuthenticationSuccess object:nil userInfo:ret];
                  });
Run Code Online (Sandbox Code Playgroud)

我想知道为什么它冻结在那里,如果有人有任何提示.

Ali*_*are 55

关于冻结提示的问题的第二部分:

调用dispatch_sync队列时,请始终验证此队列是否已经是当前队列(dispatch_get_current_queue()).因为dispatch_sync将块作为第一个参数传递给队列,然后在继续之前等待执行该块.

因此,如果dispatch_get_current_queue()您排队的队列和队列相同,即您的情况下的主队列,主队列将阻止对dispatch_sync的调用,直到...主队列执行块,但它不能,当队列被阻塞时,你在这里遇到了一个漂亮的僵局.

一个解决方案([编辑]直到iOS6):

dispatch_queue_t main = dispatch_get_main_queue();
dispatch_block_t block = ^
              {
                  [[NSNotificationCenter defaultCenter] postNotificationName:kNotificationAuthenticationSuccess object:nil userInfo:ret];
              };
if (dispatch_get_current_queue() == main)
  block(); // execute the block directly, as main is already the current active queue
else
  dispatch_sync(main, block); // ask the main queue, which is not the current queue, to execute the block, and wait for it to be executed before continuing
Run Code Online (Sandbox Code Playgroud)

[编辑]小心,dispatch_get_current_queue()仅用于调试目的而从未投入生产.实际上,dispatch_get_current_queue自iOS6.1.3起就被弃用了.

如果您处于主队列的特定情况(仅与主线程相关联),则可以[NSThread isMainThread]按@ meaning-matters的建议进行测试.


顺便问一下,你确定你需要dispatch_sync在你的情况下吗?我想稍后发送你的通知,避免阻塞直到它被发送,在你的情况下是可以接受的,所以你也可以考虑使用dispatch_async(而不是使用dispatch_sync并需要队列比较条件),这也可以避免死锁问题.

  • 关于`dispatch_get_current_queue()`的警告+1 (2认同)

mea*_*ers 40

dispatch_get_current_queue()从iOS 6开始被弃用,并且在iOS 6.1.3的主线程上dispatch_get_current_queue() == dispatch_get_main_queue()被发现false.

在iOS 6及更高版本中,只需:

dispatch_block_t block = ^
{
    <your code here>
};

if ([NSThread isMainThread])
{
    block();
}
else
{
    dispatch_sync(dispatch_get_main_queue(), block);
}
Run Code Online (Sandbox Code Playgroud)

  • 仍在iOS 8.2上工作. (2认同)