2011-10-19 7 views
36

でハング。私はこの問題を解決するために頑張った。私はブロックを構築し、メインスレッド上でそれを実行しようとする単体テストを持っています。ただし、ブロックは実際には実行されないため、同期ディスパッチであるためテストがハングします。dispatch_sync私はXcodeのユニットテストフレームワーク、SenTestingKitを内蔵したいくつかのグランドセントラルディスパッチ・コードをテストするいくつかのトラブルユニットを備えたユニットテスト

- (void)testSample { 

    dispatch_sync(dispatch_get_main_queue(), ^(void) { 
     NSLog(@"on main thread!"); 
    }); 

    STFail(@"FAIL!"); 
} 

これがハングアップするテスト環境について教えてください。

+3

良い質問と私は正解を楽しみにしています。私は、メインキューのdispatch_syncを使用するとデッドロックになり、一般的にはそれを避けることが何度も見つかった。 –

+0

@ D.C。数回またはいつも?私はあなたが 'dispatch_sync(dispatch_get_main_queue()' **をメインスレッド上で**デッドロックを作成しないようにする方法が好奇妙です!) – Honey

答えて

99

dispatch_syncは、指定されたキュー上のブロックを実行し、それが完了するのを待ちます。この場合、キューはメインディスパッチキューです。メインキューは、FIFO(先入れ先出し)順序でメインスレッド上のすべての操作を実行します。つまり、dispatch_syncを呼び出すたびに、新しいブロックは行の最後に置かれ、キュー内のそれ以前のすべてのブロックが完了するまで実行されません。

問題ここでは、あなただけのキューに入れられたブロックは、メインスレッド-しばらくは現在、メインスレッド上で実行されているあるtestSample方法で実行するために待機している行の終わりであるということです。現在のメソッド(それ自体)がを終了するまで、キューの最後のブロックはメインスレッドにアクセスできません。メインスレッドを使用します。ただし、dispatch_syncは、ディスパッチキュー上で実行するブロックオブジェクトを送信し、そのブロックが完了するまで待機します。

+1

優秀、奥深い説明のためにありがとう – Drewsmits

+1

素敵です。 (a)私が他のスレッドにいるかどうかをどうやって調べることができますか?そして、(b)どのようにして私のコードを実行したのでしょうか?メインスレッドのコードが最初に置かれますか?手がかりが歓迎されるでしょう:) –

+0

これはデッドロックの例と考えられますか? – Pescolly

7

dispatch_syncまたはdispatch_asyncを使用するかどうかにかかわらず、常にSTFail()が呼び出され、テストが失敗することがあります。

さらに重要なのは、BJホメロスのは、説明したように、あなたがメインキューに同期何かを実行する必要がある場合、あなたはあなたがメインキューまたはどうなるデッドロックになっていないことを確認しなければなりません。メインキューにいる場合は、ブロックを通常の関数として実行するだけです。

希望はこのことができます:あなたがメインキュー上で、同期し利用できるようにメインキューを待つ場合

- (void)testSample { 

    __block BOOL didRunBlock = NO; 
    void (^yourBlock)(void) = ^(void) { 
     NSLog(@"on main queue!"); 
     // Probably you want to do more checks here... 
     didRunBlock = YES; 
    }; 

    // 2012/12/05 Note: dispatch_get_current_queue() function has been 
    // deprecated starting in iOS6 and OSX10.8. Docs clearly state they 
    // should be used only for debugging/testing. Luckily this is our case :) 
    dispatch_queue_t currentQueue = dispatch_get_current_queue(); 
    dispatch_queue_t mainQueue = dispatch_get_main_queue(); 

    if (currentQueue == mainQueue) { 
     blockInTheMainThread(); 
    } else { 
     dispatch_sync(mainQueue, yourBlock); 
    } 

    STAssertEquals(YES, didRunBlock, @"FAIL!"); 
} 
6

は、あなたが実際に長い時間を待つことになります。あなたは、あなたがまだメインスレッドにいないことを確認するためにテストする必要があります。

2

dispatch_get_current_queue() 

が廃止されているので、あなたがメインスレッド上にあるかどうかを確認するために

[NSThread isMainThread] 

を使用することができ、フォローアップします。

だから、あなたが行うことができ、上記の他の回答を使用して:あなたは最初の家を出すために自分のためにを待たなければならない場合

- (void)testSample 
{ 
    BOOL __block didRunBlock = NO; 
    void (^yourBlock)(void) = ^(void) { 
     NSLog(@"on main queue!"); 
     didRunBlock = YES; 
    }; 

    if ([NSThread isMainThread]) 
     yourBlock(); 
    else 
     dispatch_sync(dispatch_get_main_queue(), yourBlock); 

    STAssertEquals(YES, didRunBlock, @"FAIL!"); 
} 
+1

メインスレッドを実行しても、メインキューで実行されているとは限りません。彼らは別のものです。 **メインキューはメインスレッド**上で実行されますが、他のキューが実行されている可能性があります。 –

1

あなたが家を出るのでしょうか?あなたは正しいと推測しました!いいえ! :基本的に

場合:あなたはFooQueue上ある

  1. 。あなたは、シリアル方法で、すなわちsyncを使用してメソッドを呼び出し、FooQueue上で実行にしたい
  2. main_queueである必要はありません)。

あなたが家にいないことは決してありません。

キューから降りるのを待つ必要があるため、ディスパッチは行われません。

関連する問題