標籤:ios www 時間 hsi alt def bsp 使用 obj
訊號量就是一個資源計數器,對訊號量有兩個操作來達到互斥,分別是P和V操作。 一般情況是這樣進行臨界訪問或互斥訪問的: 設訊號量值為1, 當一個進程1運行是,使用資源,進行P操作,即對訊號量值減1,也就是資源數少了1個。這是訊號量值為0。系統中規定當訊號量值為0是,必須等待,知道訊號量值不為零才能繼續操作。 這時如果進程2想要運行,那麼也必須進行P操作,但是此時訊號量為0,所以無法減1,即不能P操作,也就阻塞。這樣就到到了進程1排他訪問。 當進程1運行結束後,釋放資源,進行V操作。資源數重新加1,這是訊號量的值變為1. 這時進程2發現資源數不為0,訊號量能進行P操作了,立即執行P操作。訊號量值又變為0.次數進程2咱有資源,排他訪問資源。 這就是訊號量來控制互斥的原理
定義:
1、訊號量:就是一種可用來控制訪問資源的數量的標識,設定了一個訊號量,線上程訪問之前,加上訊號量的處理,則可告知系統按照我們指定的訊號量數量來執行多個線程。
其實,這有點類似鎖機制了,只不過訊號量都是系統協助我們處理了,我們只需要在執行線程之前,設定一個訊號量值,並且在使用時,加上訊號量處理方法就行了。
2、訊號量主要有3個函數,分別是:
//建立訊號量,參數:訊號量的初值,如果小於0則會返回NULLdispatch_semaphore_create(訊號量值) //等待降低訊號量dispatch_semaphore_wait(訊號量,等待時間) //提高訊號量dispatch_semaphore_signal(訊號量)
簡單的介紹一下這三個函數,第一個函數有一個整形的參數,我們可以理解為訊號的總量,dispatch_semaphore_signal是發送一個訊號,自然會讓訊號總量加1,dispatch_semaphore_wait等待訊號,當訊號總量少於0的時候就會一直等待,否則就可以正常的執行,並讓訊號總量-1,根據這樣的原理,我們便可以快速的建立一個並發控制來同步任務和有限資源存取控制。 3、先來一個簡單的例子
// 建立訊號量,並且設定值為10 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++) { // 由於是非同步執行的,所以每次迴圈Block裡面的dispatch_semaphore_signal根本還沒有執行就會執行dispatch_semaphore_wait,從而semaphore-1.當迴圈10此後,semaphore等於0,則會阻塞線程,直到執行了Block的dispatch_semaphore_signal 才會繼續執行 dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); dispatch_async(queue, ^{ NSLog(@"訊號量-index=%i",i); sleep(2); // 每次發送訊號則semaphore會+1, dispatch_semaphore_signal(semaphore); }); }
發現,任務是10個一組,隔2秒執行一組。可以理解為最大並發數為10。
3、是不是有點感覺了,那再來一個例子,就更清楚了
-(void)dispatchSignal{ //crate的value表示,最多幾個資源可訪問 dispatch_semaphore_t semaphore = dispatch_semaphore_create(2); dispatch_queue_t quene = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //任務1 dispatch_async(quene, ^{ dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); NSLog(@"run task 1"); sleep(1); NSLog(@"complete task 1"); dispatch_semaphore_signal(semaphore); });<br> //任務2 dispatch_async(quene, ^{ dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); NSLog(@"run task 2"); sleep(1); NSLog(@"complete task 2"); dispatch_semaphore_signal(semaphore); });<br> //任務3 dispatch_async(quene, ^{ dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); NSLog(@"run task 3"); sleep(1); NSLog(@"complete task 3"); dispatch_semaphore_signal(semaphore); }); }
執行結果:
總結:由於設定的訊號值為2,先執行兩個線程,等執行完一個,才會繼續執行下一個,保證同一時間執行的線程數不超過2。
這裡我們擴充一下,假設我們設定訊號值=1
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
那麼結果就是:
如果設定訊號值=3
dispatch_semaphore_t semaphore = dispatch_semaphore_create(3);
那麼結果就是:
其實設定為3,就是不限制線程執行了,因為一共才只有3個線程。
參考資料:
淺談GCD中的訊號量iOS GCD中級篇 - dispatch_semaphore(訊號量)的理解及使用
iOS 訊號量