dispatch_semaphore使用

4288 ワード

想像のシーン:1.10個のファイルをダウンロードしたいのですが、同じ時間に2つのファイルをダウンロード状態にしたいだけです.GCDでどうやって実現しますか?この問題は,同時制御に関し,信号量を用いて良好に制御できる.信号量は整形値であり、初期カウント値を有し、信号通知と待機の2つの動作をサポートする.1つの信号量が信号によって通知されると、そのカウントは増加する.1つのスレッドが1つの信号量で待機すると、必要に応じてスレッドはカウンタがゼロより大きくなるまでブロックされ、スレッドはこのカウントを減少させます.GCDにはsemaphoreに関する3つの関数があります.それぞれ:
  dispatch_semaphore_create       semaphore
  dispatch_semaphore_signal         ,    +1
  dispatch_semaphore_wait        

彼らの様子を見てはいけない.このsemaphoreの単語はまだ知らないので、渋い感じがしますが、実際に使うと簡単だと気づきます.このAPIは3つの関数について簡単で、関数のパラメータも一般的に1、2つです.信号量は駐車場の例で類比でき、分かりやすい.もし1つの駐車場に3つの空きスペースがあれば、駐車場の外に信号灯が3つの空きスペースがあることを示しています.この時、駐車場の外に5台の車が来て、前の3量の車は順番に駐車場に入って、1台の車に入るたびに、信号灯は1を減らして、信号灯が0になると、駐車スペースがないことを意味して、外の車は待つしかなくて、駐車場に入ることができません.1台の車が走ると、信号に1が加算され、空きスペースがあることを意味し、1台の車が入ることができます.dispatch_queue_createは信号を作成することですdispatch_semaphore_waitは駐車場の外でサイレンを鳴らして駐車場に入る準備をしています.この時、空き車があれば、スムーズに入ることができます.信号灯を1減らして、駐車スペースがない車を入れて、信号灯の数が1より大きいまで外で待っています.すぐにdispatch_に入ります.semaphore_signalは信号の数+1を譲って、外に待っている車があれば入ってもいいと教えてくれます.
一.APIの紹介
1.dispatch_semaphore_create
/*!
 * @function dispatch_semaphore_create
 *
 * @abstract
 * Creates new counting semaphore with an initial value.
 *                  
 * @discussion
 * Passing zero for the value is useful for when two threads need to reconcile
 * the completion of a particular event. Passing a value greater than zero is
 * useful for managing a finite pool of resources, where the pool size is equal
 * to the value.
 *  0                    ,   0        ,               
 * @param value
 * The starting value for the semaphore. Passing a value less than zero will
 * cause NULL to be returned.
 *       。    0     NULL
 * @result
 * The newly created semaphore, or NULL on failure.
 */
dispatch_semaphore_t
dispatch_semaphore_create(long value);

2.dispatch_semaphore_wait
/*!
 * @function dispatch_semaphore_wait
 *
 * @abstract
 * Wait (decrement) for a semaphore.
 *    (  )   
 * @discussion
 * Decrement the counting semaphore. If the resulting value is less than zero,
 * this function waits for a signal to occur before returning.
 *      。       0,                   
 * @param dsema
 * The semaphore. The result of passing NULL in this parameter is undefined.
 *      。 NULL        
 * @param timeout
 * When to timeout (see dispatch_time). As a convenience, there are the
 * DISPATCH_TIME_NOW and DISPATCH_TIME_FOREVER constants.
 *      。    ,         :DISPATCH_TIME_NOW DISPATCH_TIME_FOREVER
 * @result
 * Returns zero on success, or non-zero if the timeout occurred.
 *   0    ,   0         
 */
long
dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout);

3.dispatch_semaphore_signal
/*!
 * @function dispatch_semaphore_signal
 *
 * @abstract
 * Signal (increment) a semaphore.
 *    (  )     
 * @discussion
 * Increment the counting semaphore. If the previous value was less than zero,
 * this function wakes a waiting thread before returning.
 *                   
 * @param dsema The counting semaphore.
 * The result of passing NULL in this parameter is undefined.
 *   0     
 * @result
 * This function returns non-zero if a thread is woken. Otherwise, zero is
 * returned.
 *     0        。  ,  0
 */
long
dispatch_semaphore_signal(dispatch_semaphore_t dsema);

二.適用
応用も簡単になりました
    //           0
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(2);
    _semaphore = semaphore;
    
    for (int i = 0; i < 10; i ++ ) {
        
        dispatch_async(globalqueue, ^{
            
            //          1,        ,     0,       。
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            sleep(3);
            NSLog(@"---------  %d  ---%@",i,[NSThread currentThread]);
            //      ,     1,        
            dispatch_semaphore_signal(semaphore);
            
        });
    }

forループを使用して10個のタスクをパラレルキューに追加します.通常、10個のタスクが同時に実行されます.dispatch_の使用semaphoreは、同じ時刻に2つのタスクしか実行できないことを制御します.
dispatch_semaphoreはまた、タスク1およびタスク2のような2つのタスクの実行順序を制御し、イベント信号量0のsemaphoreオブジェクトを作成し、タスク1の前にdispatch_を使用することもできる.semaphore_wait関数はブロックされ、待機信号量が0より大きいタスク2が完了したときに信号を送信し、タスク1を実行させる.これにより、タスク2が先に完了し、タスク1が完了するように制御できます.