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



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

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

如果有人有任何线索的话,我想知道它为什么会在那里结冰。

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

在队列上调用dispatch_sync时,始终验证此队列是否已经是当前队列dispatch_get_current_queue())。因为dispatch_sync将在作为第一个参数传递的队列中对您的块进行排队,然后将等待此块执行后再继续

因此,如果dispatch_get_current_queue()和您将块排入队列的队列相同,即您的情况下的主队列,则主队列将在调用dispatch_sync时阻塞,直到…主队列执行了块,但它不能,因为队列被阻塞了,并且您在这里有一个漂亮的死锁

一种解决方案([EDIT]直到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

[EDIT]请注意,dispatch_get_current_queue()仅用于调试目的,绝不用于生产。事实上,自iOS6.1.3以来,dispatch_get_current_queue已被弃用。

如果您处于主队列(仅与主线程关联)的特定情况下,您可以按照@meansingmatters的建议测试[NSThread isMainThread]


顺便问一下,你确定你的情况下需要dispatch_sync吗?我想,在您的情况下,晚一点发送通知,避免在发送之前进行阻塞是可以接受的,所以您也可以考虑使用dispatch_async(而不是使用dispatch_sync并需要队列比较条件),这也可以避免死锁问题。

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

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

dispatch_block_t block = ^
{
    <your code here>
};
if ([NSThread isMainThread])
{
    block();
}
else
{
    dispatch_sync(dispatch_get_main_queue(), block);
}

最新更新