iOS - dispatch_semaphoreとNSCondition(回転)

4225 ワード

GCD信号量制御同時(dispatch_semaphore)


一連のスレッドを処理する場合、数が一定量に達すると、以前はNSOperationQueueを使用して同時制御を処理することを選択していたかもしれませんが、どのようにしてGCDで迅速に同時制御を制御するのでしょうか.答えはdispatch_semaphore. 信号量は整形値であり、初期カウント値を有し、信号通知と待機の2つの動作をサポートする.1つの信号量が信号によって通知されると、そのカウントは増加する.1つのスレッドが1つの信号量で待機すると、必要に応じてカウンタがゼロより大きくなるまでスレッドがブロックされ、スレッドはこのカウントを減少させます.GCDの3つの関数はsemaphoreの操作で、それぞれ:1、dispatch_semaphore_create semaphore 2、dispatch_を作成semaphore_Signalは1つの信号3、dispatch_を送信するsemaphore_wait待機信号
次の3つの関数について説明します.
(1)dispatch_semaphore_createの宣言:dispatch_semaphore_t dispatch_semaphore_create(long value); 入力パラメータはlongで、dispatch_を出力します.semaphore_tタイプでvalueの信号量.ここで入力されるパラメータvalueは0以上でなければならないことに注意してください.そうしないとdispatch_semaphore_createはNULLを返します.
(2)dispatch_semaphore_Signalの宣言:long dispatch_semaphore_signal(dispatch_semaphore_t dsema)という関数は、入力された信号量dsemaの値に1を加える.(戻り値については、後で話します)
(3) dispatch_semaphore_waitの宣言:long dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout); この関数は、入力された信号量dsemaの値を1減少させる.この関数の役割は、dsema信号量の値が0より大きい場合、その関数のスレッドは次の文を実行し続け、信号量の値を1減少させることである.desemaの値が0の場合、この関数は、現在のスレッド待ちtimeout(timeoutのタイプがdispatch_time_tであり、整形またはfloat型数に直接入力できないことに注意)をブロックし、待ち期間desemaの値がdispatch_semaphore_Signal関数に1が加算され、この関数(すなわちdispatch_semaphore_wait)が位置するスレッドが信号量を取得すると、信号量を下向きに実行し続け、1を減算する.待機中に信号量が取得されなかったり、信号量の値が0のままであったりした場合、timeoutまで待つと、スレッドはその後の文を自動的に実行します.
(4)dispatch_semaphore_signalの戻り値はlongタイプであり、戻り値が0の場合、現在スレッドが処理を待っていない信号量を示し、その処理の信号量の値に1を足すとよい.戻り値が0でない場合、現在(1つまたは複数の)スレッドが処理を待機している信号量を表し、この関数は待機しているスレッド(スレッドに優先度がある場合、最も優先度の高いスレッドを起動し、そうでない場合、ランダムに起動する)を起動します.  dispatch_semaphore_waitの戻り値もlong型です.0を返すと、timeoutの前に関数のスレッドが正常に起動されたことを示します.戻り値が0でない場合はtimeoutが発生することを示します.
(5)信号量については,一般的には駐車にたとえることができる.駐車場は4台余っているので、同時に4台来ても停められます.もしこの時に5台の車が来たら、1台は待つ必要があります.信号量の値は残りの駐車スペースの数に相当し、dispatch_semaphore_wait関数は車が来たことに相当しますdispatch_semaphore_signalは車を1台歩いたことに相当する.駐車スペースの残りの数は初期化時にすでに指定されており(dispatch_semaphore_create(long value))、dispatch_を1回呼び出すsemaphore_signalでは、残りの駐車スペースが1つ増えます.一度dispatchを呼び出すsemaphore_waitの残りの駐車スペースは1つ減少します.残りの駐車スペースが0の場合、再利用(すなわちdispatch_semaphore_waitを呼び出す)は待つしかありません.同時に何台かの車が1つの駐車スペースを待っている可能性があります.一部の車主は辛抱強くなくて、自分に待ち時間を設定して、この時間内に駐車スペースを待てないで行って、待っていたら中に入って駐車します.一部の車主はここに車を止めたようなので、ずっと待っています.
簡単な例:
dispatch_group_t group = dispatch_group_create();   
dispatch_semaphore_t semaphore = dispatch_semaphore_create(10);   
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);   
for (int i = 0; i < 100; i++)   
{   
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);   
    dispatch_group_async(group, queue, ^{   
    NSLog(@"%i",i);   
     sleep(2);   
     dispatch_semaphore_signal(semaphore);   
    });   
}   
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);   
dispatch_release(group);   
dispatch_release(semaphore);   

このコードを簡単に紹介すると、最初に値を10にしたsemaphoreが作成され、forループのたびに新しいスレッドが作成され、スレッドが終了すると信号が送信され、スレッドが作成される前に信号が待機するため、同時に10個のスレッドが作成されるとforループがブロックされ、スレッドが終了するまで1つの信号が追加されて実行され、同時制御が形成されます.上記のように、同時数10のスレッドキューです.

NSConditionの使い方


NSConditionを使用して、マルチスレッドの同期を実現し、すなわち、生産者の消費者問題を実現することができる.
基本的な考え方は、まず共通のNSConditionインスタンスを作成することです.そして:消費者はロックを取得し、製品を取り、もしなければwaitは、スレッドが製品を消費することを呼び覚ますまでロックを解放します.生産者が製品を製造するには、まずロックを取得し、生産し、signalを再発行することで、waitの消費者を呼び覚ますことができます.
 (IBAction)conditionTest:(id)sender
{
    NSLog(@"begin condition works!");
    products = [[NSMutableArray alloc] init];
    condition = [[NSCondition alloc] init];
     
    [NSThread detachNewThreadSelector:@selector(createProducter) toTarget:self withObject:nil];
    [NSThread detachNewThreadSelector:@selector(createConsumenr) toTarget:self withObject:nil];
}
 
- (void)createConsumenr
{
    [condition lock];
    while ([products count] == 0) {
        NSLog(@"wait for products");
        [condition wait];
    }
    [products removeObjectAtIndex:0];
    NSLog(@"comsume a product");
    [condition unlock];
}
 
- (void)createProducter
{
    [condition lock];
    [products addObject:[[NSObject alloc] init]];
    NSLog(@"produce a product");
    [condition signal];
    [condition unlock];
}

コードは上記の通りです!