IOS信號量(PV操作)

本文為轉載資料,原文地址: http://www.lxweimin.com/p/02821f9d7777

一、信號量的簡單介紹:

1.信號量:

信號量(Semaphore),有時被稱為信號燈,是在多線程環境下使用的一種設施,是可以用來保證兩個或多個關鍵代碼段不被并發調用。在進入一個關鍵代碼段之前,線程必須獲取一個信號量;一旦該關鍵代碼段完成了,那么該線程必須釋放信號量。其它想進入該關鍵代碼段的線程必須等待直到第一個線程釋放信號量。為了完成這個過程,需要創建一個信號量VI,然后將Acquire Semaphore VI以及Release Semaphore VI分別放置在每個關鍵代碼段的首末端。確認這些信號量VI引用的是初始創建的信號量。

2.特性:

抽象的來講,信號量的特性如下:信號量是一個非負整數(車位數),所有通過它的線程/進程(車輛)都會將該整數減一(通過它當然是為了使用資源),當該整數值為零時,所有試圖通過它的線程都將處于等待狀態。在信號量上我們定義兩種操作: Wait(等待) 和 Release(釋放)。當一個線程調用Wait操作時,它要么得到資源然后將信號量減一,要么一直等下去(指放入阻塞隊列),直到信號量大于等于一時。Release(釋放)實際上是在信號量上執行加操作,對應于車輛離開停車場,該操作之所以叫做“釋放”是因為釋放了由信號量守護的資源。

3.描述:

以一個停車場的運作為例。簡單起見,假設停車場只有三個車位,一開始三個車位都是空的。這時如果同時來了五輛車,看門人允許其中三輛直接進入,然后放下車攔,剩下的車則必須在入口等待,此后來的車也都不得不在入口處等待。這時,有一輛車離開停車場,看門人得知后,打開車攔,放入外面的一輛進去,如果又離開兩輛,則又可以放入兩輛,如此往復。

在這個停車場系統中,車位是公共資源,每輛車好比一個線程,看門人起的就是信號量的作用。

4.發展史:

1965年,荷蘭學者Edsger Dijkstra提出的信號量(Semaphores)機制是一種卓有成效的進程同步工具,在長期廣泛的應用中,信號量機制得到了極大的發展,它從整型信號量經記錄型信號量,進而發展成為“信號量集機制”,現在信號量機制已經被廣泛的應用到單處理機和多處理機系統以及計算機網絡中。

5.在IOS系統GCD的semaphore.h頭文件中提供三個方法進行PV操作

在IOS系統GCD的semaphore.h頭文件中提供三個方法進行PV操作// 這value是初始化多少個信號量1.dispatch_semaphore_create(longvalue);// 這個方法是P操作對信號量減一,dsema這個參數表示對哪個信號量進行減一,如果該信號量為0則等待,timeout這個參數則是傳入等待的時長。2.dispatch_semaphore_wait(dispatch_semaphore_tdsema,dispatch_time_ttimeout);// 這個方法是V操作對信號量加一,dsema這個參數表示對哪個信號量進行加一3.dispatch_semaphore_signal(dispatch_semaphore_tdsema);

二、下面是最簡單的例子,利用信號量或同步鎖對多線程操作iphoneNumber變量進行互斥。

////? ViewController.m//? semaphoreTest2////? Created by huangxianchao on 17/05/2017.//? Copyright ? 2017 黃先超. All rights reserved.//#import"ViewController.h"@interfaceViewController()/// iphone的數量@property(nonatomic,assign)intiphoneNumber;/// 互斥用的信號量@property(nonatomic,strong) dispatch_semaphore_t semaphore;@end@implementationViewController- (void)viewDidLoad {? ? [superviewDidLoad];self.iphoneNumber =1000;// 初始化1個信號量self.semaphore = dispatch_semaphore_create(1);/// 通過信號量進行互斥,開啟三個窗口(線程)同時賣iphoneNSThread*thread1 = [[NSThreadalloc] initWithTarget:selfselector:@selector(sellIphone) object:nil];? ? thread1.name =@"窗口1";NSThread*thread2 = [[NSThreadalloc] initWithTarget:selfselector:@selector(sellIphone) object:nil];? ? thread2.name =@"窗口2";NSThread*thread3 = [[NSThreadalloc] initWithTarget:selfselector:@selector(sellIphone) object:nil];? ? thread3.name =@"窗口3";/// 通過同步鎖進行互斥,開啟三個窗口(線程)同時賣iphone//? ? NSThread *thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(sellIphoneWithSynchronization) object:nil];//? ? thread1.name = @"窗口1";//? ? NSThread *thread2 = [[NSThread alloc] initWithTarget:self selector:@selector(sellIphoneWithSynchronization) object:nil];//? ? thread2.name = @"窗口2";//? ? NSThread *thread3 = [[NSThread alloc] initWithTarget:self selector:@selector(sellIphoneWithSynchronization) object:nil];//? ? thread3.name = @"窗口3";[thread1 start];? ? [thread2 start];? ? [thread3 start];}/// 通過信號量達到互斥- (void)sellIphone{while(1) {// P操作對信號量進行減一,然后信號量變0,限制其他窗口(線程)進入dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);if(self.iphoneNumber >0)// 檢查還有沒iphone可賣{NSLog(@"賣出iphone剩下%d臺iphone",--self.iphoneNumber);? ? ? ? }else{NSLog(@"iphone沒有庫存了");return;? ? ? ? }// V操作對信號量進行加一,然后信號量為1,其他窗口(線程)就能進入了dispatch_semaphore_signal(self.semaphore);? ? }}/// 通過同步鎖進行互斥,通過同步鎖會比通過信號量控制的方式多進入該臨界代碼(線程數量-1)次- (void)sellIphoneWithSynchronization{while(1) {@synchronized(self) {if(self.iphoneNumber >0)// 檢查還有沒iphone可賣{NSLog(@"%@賣出iphone剩下%d臺iphone",[NSThreadcurrentThread].name,--self.iphoneNumber);? ? ? ? ? ? }else{NSLog(@"iphone沒有庫存了");return;? ? ? ? ? ? }? ? ? ? }? ? }}@end

注意:如果不理解可以注釋信號量代碼或者同步鎖代碼仔細觀察iphoneNumber值的變化

三、控制同一個信號量(臨界資源)下的相關線程最大的并發數

////? ViewController.m//? samephoreTest3////? Created by huangxianchao on 17/05/2017.//? Copyright ? 2017 黃先超. All rights reserved.//#import"ViewController.h"@interfaceViewController()@end@implementationViewController- (void)viewDidLoad {? ? [superviewDidLoad];//這里的value控制基于semaphore這個信號量的相關線程最多幾個線程并發運行dispatch_semaphore_t semaphore = dispatch_semaphore_create(2);dispatch_queue_tquene = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);//線程1dispatch_async(quene, ^{? ? ? ? dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);NSLog(@"thread1 start");? ? ? ? dispatch_semaphore_signal(semaphore);NSLog(@"thread1 finish");? ? });//線程2dispatch_async(quene, ^{? ? ? ? dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);NSLog(@"thread2 start");? ? ? ? dispatch_semaphore_signal(semaphore);NSLog(@"thread2 finish");? ? });//線程3dispatch_async(quene, ^{? ? ? ? dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);NSLog(@"thread3 start");? ? ? ? dispatch_semaphore_signal(semaphore);NSLog(@"thread3 finish");? ? });}@end

下面是兩個現實生活的例子

一、這是關于公交車上司機和售票員的配合問題。

1.司機需要等待售票員關門后才能開車

2.售票員需要等待司機停車后才能開門

// 司機是否停車的信號量,dispatch_semaphore_t semaphoreStopBused = dispatch_semaphore_create(1);// 售票員是否關門的信號量dispatch_semaphore_t semaphoreCloseDoored = dispatch_semaphore_create(0);// 拿到全局隊列dispatch_queue_tquene = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);// 司機的相關操作dispatch_async(quene, ^{while(1) {// 司機等待售票員關門,DISPATCH_TIME_FOREVER表示這個信號量如果是0就一直等待這個信號量dispatch_semaphore_wait(semaphoreCloseDoored, DISPATCH_TIME_FOREVER);NSLog(@"司機開車");NSLog(@"司機停車");// 司機已關門,停車的信號量加一dispatch_semaphore_signal(semaphoreStopBused);? ? ? ? }? ? });// 售票員的相關操作dispatch_async(quene, ^{while(1) {// 售票員等待司機停車dispatch_semaphore_wait(semaphoreStopBused, DISPATCH_TIME_FOREVER);NSLog(@"售票員開門");NSLog(@"售票員關門");// 售票員已經關門,關門的信號量加一dispatch_semaphore_signal(semaphoreCloseDoored);? ? ? ? }? ? });

注意:

1.semaphoreStopBused和semaphoreCloseDoored信號量只能同時有一個是1,這值表示當前是停車了還是關門了,會觸發相關的流程

2.讓semaphoreCloseDoored為1,semaphoreStopBused為0試試,觀察最開始的流程走的順序有什么不同

二、生產和銷售的問題

/*

生產和銷售的線程同時操縱iphoneNumber變量為了保證數據的正確性,并且生產到5臺iphone就不再生產了。

*/// iphone數量__blockintiphoneNumber =0;// 生產和銷售的互斥dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);// 拿到全局隊列dispatch_queue_tquene = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);// 生產iphonedispatch_async(quene, ^{while(1) {// 生產和銷售的互斥,等待信號量dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);if(iphoneNumber <5) {NSLog(@"生產iphone,目前有%d臺",++iphoneNumber);? ? ? ? ? ? }? ? ? ? ? ? dispatch_semaphore_signal(semaphore);? ? ? ? }? ? });// 銷售iphonedispatch_async(quene, ^{while(1) {// 生產和銷售的互斥,等待信號量dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);if(iphoneNumber >0) {NSLog(@"賣掉一臺iphone,目前有%d臺",--iphoneNumber);? ? ? ? ? ? }? ? ? ? ? ? dispatch_semaphore_signal(semaphore);? ? ? ? }? ? });

22702FAC-1779-4C57-86A1-73C7E74A1121.png

上面圖的結果是正確的,生產和銷售后的數據都能對的上。

如果把代碼更改為下面的情況,就是不用信號量去做互斥的話,看下圖生成的錯誤結果圖

/*

生產和銷售的互斥保證得到的數據是正確的,并且生產到5臺iphone就不再生產了

*/// iphone數量__blockintiphoneNumber =0;// 生產和銷售的互斥//? ? dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);// 拿到全局隊列dispatch_queue_tquene = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);// 生產iphonedispatch_async(quene, ^{while(1) {// 生產和銷售的互斥,等待信號量//? ? ? ? ? ? dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);if(iphoneNumber <5) {NSLog(@"生產iphone,目前有%d臺",++iphoneNumber);? ? ? ? ? ? }//? ? ? ? ? ? dispatch_semaphore_signal(semaphore);}? ? });// 銷售iphonedispatch_async(quene, ^{while(1) {// 生產和銷售的互斥,等待信號量//? ? ? ? ? ? dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);if(iphoneNumber >0) {NSLog(@"賣掉一臺iphone,目前有%d臺",--iphoneNumber);? ? ? ? ? ? }//? ? ? ? ? ? dispatch_semaphore_signal(semaphore);}? ? });

看下圖生成的錯誤結果圖

圖片.png

上圖的結果有兩處錯誤

1.連續生產兩次iphone后產品的數量都是5。

2.連續賣掉兩次iphone后產品的數量都是4。

參考資料:

http://baike.baidu.com/link?url=xfbl90QNrVjVE1oqELnAEYYvwI86XG_FLz-QEp9y4kn3icGzRXDwiPi4ICZ2FNhff8ho8MghcQyA0OaBRZKGMDKfUAsipmyooTWNyfdngjYkQ_krzsD_7KaSH_4PFv7y

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,247評論 6 543
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,520評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,362評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,805評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,541評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,896評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,887評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,062評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,608評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,356評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,555評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,077評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,769評論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,175評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,489評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,289評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,516評論 2 379

推薦閱讀更多精彩內容