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

时间:2012-09-11 22:56:45

标签: objective-c multithreading cocoa-touch 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];
                  });

我想知道为什么它会冻结,如果有人有任何提示。

2 个答案:

答案 0 :(得分:54)

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

在队列上调用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

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

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


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

答案 1 :(得分:39)

从iOS 6开始,不推荐使用

dispatch_get_current_queue(),而在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);
}