web-dev-qa-db-ja.com

このdispatch_sync()呼び出しがフリーズするのはなぜですか?

Kiwiテストフレームワークを使用して、アプリの認証方法をテストしています。次のようなdispatch_syncの呼び出しで、テストがフリーズします。

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

誰かヒントがあれば、なぜそこでフリーズするのか知りたいのですが。

29
teubanks

フリーズのヒントに関する質問の2番目の部分:

キューで_dispatch_sync_を呼び出す場合、このキューが現在のキューになっていないことを常に確認してくださいdispatch_get_current_queue())。 _dispatch_sync_は、最初のパラメーターとして渡されたキューでブロックをキューに入れ、次にこのブロックが実行されるのを待ってから続行します

したがって、dispatch_get_current_queue()とブロックをエンキューするキューが同じである場合、つまりメインキューの場合、メインキューはdispatch_syncの呼び出しで、ブロックが実行されるまでメインキューがブロックされます。 、しかし、キューがブロックされているため、それはできませんそしてここに美しいデッドロックがあります

1つの解決策(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()はデバッグ目的でのみ使用され、本番環境では使用されません。実際、_dispatch_get_current_queue_はiOS6.1.3以降非推奨になっています。

メインキュー(メインスレッドのみに関連付けられている)の特定のケースにいる場合は、代わりに@ meaning-mattersで提案されているように_[NSThread isMainThread]_をテストできます。


ちなみに、あなたの場合は_dispatch_sync_する必要がありますか?通知を送信するのは少し後で、送信されるまでブロックしないことは許容できると思います。そのため、(_dispatch_async_を使用してキュー比較条件を必要とする代わりに、_dispatch_sync_を使用することも検討してください。 )、デッドロックの問題も回避できます。

54
AliSoftware

dispatch_get_current_queue()はiOS6以降非推奨になり、iOS6.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);
}
40
meaning-matters