6

これが私がしなければならないことです。GCDを使用してdispatch_syncが最善の方法であることを願っています

Appdelegate の applicationDidBecomeActive コールバックに配置されている特定のクリティカル セクション コードがあります。

applicationDidBecomeActive が何回呼び出されても、1 回だけ呼び出されるように、dispatch_sync 呼び出し内にそのメソッドをまとめています。

- (void)applicationDidBecomeActive:(UIApplication *)application{    
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{    
    NSLog(@"Thread created");
    //crtical code
    [self runCriticalSection];        
});}

これは、dispatch_sync を使用して行う正しい方法ですか?

4

2 に答える 2

15

dispatch_sync()ブロックが終了するまで戻りません。つまり、 が実行を終了applicationDidBecomeActiveするまで戻りませんrunCriticalSection

これはおそらくあなたが望むものではないので、使用する必要がありますdispatch_async()(他の回答ですでに述べたように)。

runCriticalSectionただし、前のものがまだ実行されている場合は、別のものを開始したくありません。これは、「カウンティング セマフォ」(GCD の機能でもあります) を使用して実現できます。

static dispatch_semaphore_t sema; // The semaphore
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    // Initialize with count=1 (this is executed only once):
    sema = dispatch_semaphore_create(1);
});

// Try to decrement the semaphore. This succeeds if the count is still 1
// (meaning that runCriticalSection is not executing), and fails if the 
// current count is 0 (meaning that runCriticalSection is executing):
if (dispatch_semaphore_wait(sema, DISPATCH_TIME_NOW) == 0) {
    // Success, semaphore count is now 0.
    // Start asynchronous operation.
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //critical code
        [self runCriticalSection];
        // Increment the semaphore count (from 0 to 1), so that the next call
        // to applicationDidBecomeActive will start a new operation:
        dispatch_semaphore_signal(sema);
    });
}
于 2013-05-01T21:18:12.007 に答える
0

メソッドはrunCriticalSection同時にではなく複数回呼び出されるため、これがあなたが達成したいことかどうかわかりません。

dispatch_sync指定されたブロックをシリアル キュー (デフォルトの優先度グローバル キュー) に追加するだけapplicationDidBecomeActiveですrunCriticalSection。最初のブロックが実行を開始して終了すると、2 番目のブロックが開始されるため、2 つのブロックが同時に実行されることはありません。

これは予想される動作ですか?もしそうなら、dispatch_sync行く方法です。

アドオンとして:runCriticalSection重い操作を実行する場合、その操作が完了するまで、メソッドを実行するスレッド(別のスレッドから手動でメソッドを呼び出さない場合はメインdispatch_syncのスレッド)をブロックすることを検討してください。applicationDidBecomeActive

これを避けたい場合は、次のようにする必要があります。

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{    
    [self runCriticalSectionOnComplete:^{
       // If you want to perform something on completion, place it here. This is called asynchronously, without blocking the main thread.
    }];        
});

dispatch_asyncブロックがキューに追加されるとすぐに戻り、dispatch_syncブロック内のコードが完了するのを待ちます。

于 2013-05-01T20:54:21.227 に答える