Why is this dispatch_sync() call freezing?

倾然丶 夕夏残阳落幕 提交于 2019-11-27 11:35:13

For the second part of your question regarding the hint on the freeze:

When calling dispatch_sync on a queue, always verify that this queue is not already the current queue (dispatch_get_current_queue()). Because dispatch_sync will queue your block on the queue passed as the first parameter, and then will wait for this block to be executed before continuing.

So if the dispatch_get_current_queue() and the queue on which you enqueue your block are the same, namely the main queue in your case, the main queue will block on the call to dispatch_sync until… the main queue as executed the block, but it can't, as the queue is blocked, and you have a beautiful deadlock here.

One solution ([EDIT] up until 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] Be careful, dispatch_get_current_queue() is only to be used for debugging purposes and never in production. In fact, dispatch_get_current_queue is deprecated since iOS6.1.3.

If you are in the specific case of the main queue (which is associated with the main thread only), you may instead test [NSThread isMainThread] as suggested by @meaning-matters.


By the way, are you sure you need to dispatch_sync in your case? I guess sending your notification a bit later, avoiding to block until it has been sent, is acceptable in your case, so you may also consider using dispatch_async (instead of using dispatch_sync and needing the queue comparison condition), which would avoid the deadlock issue too.

dispatch_get_current_queue() is deprecated starting from iOS 6, and dispatch_get_current_queue() == dispatch_get_main_queue() was found to be false while on main thread on iOS 6.1.3.

In iOS 6 and beyond simply do:

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

if ([NSThread isMainThread])
{
    block();
}
else
{
    dispatch_sync(dispatch_get_main_queue(), block);
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!