1. 程式人生 > >GCD 訊號量控制併發 (dispatch_semaphore)

GCD 訊號量控制併發 (dispatch_semaphore)

當我們在處理一系列執行緒的時候,當數量達到一定量,在以前我們可能會選擇使用NSOperationQueue來處理併發控制,但如何在GCD中快速的控制併發呢?答案就是dispatch_semaphore,對經常做unix開發的人來講,我所介紹的內容可能就顯得非常入門級了,訊號量在他們的多執行緒開發中再平常不過了。
  訊號量是一個整形值並且具有一個初始計數值,並且支援兩個操作:訊號通知和等待。當一個訊號量被訊號通知,其計數會被增加。當一個執行緒在一個訊號量上等待時,執行緒會被阻塞(如果有必要的話),直至計數器大於零,然後執行緒會減少這個計數。
  在GCD中有三個函式是semaphore的操作,分別是:

  dispatch_semaphore_create   建立一個semaphore
  dispatch_semaphore_signal   傳送一個訊號
  dispatch_semaphore_wait    等待訊號
  簡單的介紹一下這三個函式,第一個函式有一個整形的引數,我們可以理解為訊號的總量,dispatch_semaphore_signal是傳送一個訊號,自然會讓訊號總量加1,dispatch_semaphore_wait等待訊號,當訊號總量少於0的時候就會一直等待,否則就可以正常的執行,並讓訊號總量-1,根據這樣的原理,我們便可以快速的建立一個併發控制來同步任務和有限資源訪問控制。
  1. dispatch_group_t group = dispatch_group_create();   
  2.     dispatch_semaphore_t semaphore = dispatch_semaphore_create(10);   
  3.     dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);   
  4.     for (int i = 0; i < 100; i++)   
  5.     {   
  6.         dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);   
  7.         dispatch_group_async(group, queue, ^{   
  8.             NSLog(@"%i",i);   
  9.             sleep(2);   
  10.             dispatch_semaphore_signal(semaphore);   
  11.         });   
  12.     }   
  13.     dispatch_group_wait(group, DISPATCH_TIME_FOREVER);   
  14.     dispatch_release(group);   
  15.     dispatch_release(semaphore);   

  簡單的介紹一下這一段程式碼,建立了一個初使值為10的semaphore,每一次for迴圈都會建立一個新的執行緒,執行緒結束的時候會發送一個訊號,執行緒建立之前會訊號等待,所以當同時建立了10個執行緒之後,for迴圈就會阻塞,等待有執行緒結束之後會增加一個訊號才繼續執行,如此就形成了對併發的控制,如上就是一個併發數為10的一個執行緒佇列。

簡單示例

  1. __block BOOL isok = NO;  
  2.     dispatch_semaphore_t sema = dispatch_semaphore_create(0);  
  3.     Engine *engine = [[Engine alloc] init];  
  4.     [engine queryCompletion:^(BOOL isOpen) {  
  5.         isok = isOpen;  
  6.         dispatch_semaphore_signal(sema);  
  7.     } onError:^(int errorCode, NSString *errorMessage) {  
  8.         isok = NO;  
  9.         dispatch_semaphore_signal(sema);  
  10.     }];  
  11.     dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);  
  12.     dispatch_release(sema);