IOS信號(hào)量(PV操作)

本文為轉(zhuǎn)載資料案站,原文地址: http://www.reibang.com/p/02821f9d7777

一侄柔、信號(hào)量的簡(jiǎn)單介紹:

1.信號(hào)量:

信號(hào)量(Semaphore)浑槽,有時(shí)被稱(chēng)為信號(hào)燈巫员,是在多線程環(huán)境下使用的一種設(shè)施,是可以用來(lái)保證兩個(gè)或多個(gè)關(guān)鍵代碼段不被并發(fā)調(diào)用四敞。在進(jìn)入一個(gè)關(guān)鍵代碼段之前勾缭,線程必須獲取一個(gè)信號(hào)量;一旦該關(guān)鍵代碼段完成了目养,那么該線程必須釋放信號(hào)量。其它想進(jìn)入該關(guān)鍵代碼段的線程必須等待直到第一個(gè)線程釋放信號(hào)量毒嫡。為了完成這個(gè)過(guò)程癌蚁,需要?jiǎng)?chuàng)建一個(gè)信號(hào)量VI,然后將Acquire Semaphore VI以及Release Semaphore VI分別放置在每個(gè)關(guān)鍵代碼段的首末端兜畸。確認(rèn)這些信號(hào)量VI引用的是初始創(chuàng)建的信號(hào)量努释。

2.特性:

抽象的來(lái)講,信號(hào)量的特性如下:信號(hào)量是一個(gè)非負(fù)整數(shù)(車(chē)位數(shù))咬摇,所有通過(guò)它的線程/進(jìn)程(車(chē)輛)都會(huì)將該整數(shù)減一(通過(guò)它當(dāng)然是為了使用資源)伐蒂,當(dāng)該整數(shù)值為零時(shí),所有試圖通過(guò)它的線程都將處于等待狀態(tài)肛鹏。在信號(hào)量上我們定義兩種操作: Wait(等待) 和 Release(釋放)逸邦。當(dāng)一個(gè)線程調(diào)用Wait操作時(shí),它要么得到資源然后將信號(hào)量減一在扰,要么一直等下去(指放入阻塞隊(duì)列)缕减,直到信號(hào)量大于等于一時(shí)。Release(釋放)實(shí)際上是在信號(hào)量上執(zhí)行加操作芒珠,對(duì)應(yīng)于車(chē)輛離開(kāi)停車(chē)場(chǎng)桥狡,該操作之所以叫做“釋放”是因?yàn)獒尫帕擞尚盘?hào)量守護(hù)的資源。

3.描述:

以一個(gè)停車(chē)場(chǎng)的運(yùn)作為例皱卓。簡(jiǎn)單起見(jiàn)裹芝,假設(shè)停車(chē)場(chǎng)只有三個(gè)車(chē)位,一開(kāi)始三個(gè)車(chē)位都是空的娜汁。這時(shí)如果同時(shí)來(lái)了五輛車(chē)嫂易,看門(mén)人允許其中三輛直接進(jìn)入,然后放下車(chē)攔掐禁,剩下的車(chē)則必須在入口等待炬搭,此后來(lái)的車(chē)也都不得不在入口處等待蜈漓。這時(shí),有一輛車(chē)離開(kāi)停車(chē)場(chǎng)宫盔,看門(mén)人得知后融虽,打開(kāi)車(chē)攔,放入外面的一輛進(jìn)去灼芭,如果又離開(kāi)兩輛有额,則又可以放入兩輛,如此往復(fù)彼绷。

在這個(gè)停車(chē)場(chǎng)系統(tǒng)中巍佑,車(chē)位是公共資源,每輛車(chē)好比一個(gè)線程寄悯,看門(mén)人起的就是信號(hào)量的作用萤衰。

4.發(fā)展史:

1965年,荷蘭學(xué)者Edsger Dijkstra提出的信號(hào)量(Semaphores)機(jī)制是一種卓有成效的進(jìn)程同步工具猜旬,在長(zhǎng)期廣泛的應(yīng)用中脆栋,信號(hào)量機(jī)制得到了極大的發(fā)展,它從整型信號(hào)量經(jīng)記錄型信號(hào)量洒擦,進(jìn)而發(fā)展成為“信號(hào)量集機(jī)制”椿争,現(xiàn)在信號(hào)量機(jī)制已經(jīng)被廣泛的應(yīng)用到單處理機(jī)和多處理機(jī)系統(tǒng)以及計(jì)算機(jī)網(wǎng)絡(luò)中。

5.在IOS系統(tǒng)GCD的semaphore.h頭文件中提供三個(gè)方法進(jìn)行PV操作

在IOS系統(tǒng)GCD的semaphore.h頭文件中提供三個(gè)方法進(jìn)行PV操作// 這value是初始化多少個(gè)信號(hào)量1.dispatch_semaphore_create(longvalue);// 這個(gè)方法是P操作對(duì)信號(hào)量減一熟嫩,dsema這個(gè)參數(shù)表示對(duì)哪個(gè)信號(hào)量進(jìn)行減一秦踪,如果該信號(hào)量為0則等待,timeout這個(gè)參數(shù)則是傳入等待的時(shí)長(zhǎng)掸茅。2.dispatch_semaphore_wait(dispatch_semaphore_tdsema,dispatch_time_ttimeout);// 這個(gè)方法是V操作對(duì)信號(hào)量加一椅邓,dsema這個(gè)參數(shù)表示對(duì)哪個(gè)信號(hào)量進(jìn)行加一3.dispatch_semaphore_signal(dispatch_semaphore_tdsema);

二、下面是最簡(jiǎn)單的例子昧狮,利用信號(hào)量或同步鎖對(duì)多線程操作iphoneNumber變量進(jìn)行互斥希坚。

////? ViewController.m//? semaphoreTest2////? Created by huangxianchao on 17/05/2017.//? Copyright ? 2017 黃先超. All rights reserved.//#import"ViewController.h"@interfaceViewController()/// iphone的數(shù)量@property(nonatomic,assign)intiphoneNumber;/// 互斥用的信號(hào)量@property(nonatomic,strong) dispatch_semaphore_t semaphore;@end@implementationViewController- (void)viewDidLoad {? ? [superviewDidLoad];self.iphoneNumber =1000;// 初始化1個(gè)信號(hào)量self.semaphore = dispatch_semaphore_create(1);/// 通過(guò)信號(hào)量進(jìn)行互斥,開(kāi)啟三個(gè)窗口(線程)同時(shí)賣(mài)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";/// 通過(guò)同步鎖進(jìn)行互斥陵且,開(kāi)啟三個(gè)窗口(線程)同時(shí)賣(mài)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];}/// 通過(guò)信號(hào)量達(dá)到互斥- (void)sellIphone{while(1) {// P操作對(duì)信號(hào)量進(jìn)行減一裁僧,然后信號(hào)量變0,限制其他窗口(線程)進(jìn)入dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);if(self.iphoneNumber >0)// 檢查還有沒(méi)iphone可賣(mài){NSLog(@"賣(mài)出iphone剩下%d臺(tái)iphone",--self.iphoneNumber);? ? ? ? }else{NSLog(@"iphone沒(méi)有庫(kù)存了");return;? ? ? ? }// V操作對(duì)信號(hào)量進(jìn)行加一慕购,然后信號(hào)量為1聊疲,其他窗口(線程)就能進(jìn)入了dispatch_semaphore_signal(self.semaphore);? ? }}/// 通過(guò)同步鎖進(jìn)行互斥,通過(guò)同步鎖會(huì)比通過(guò)信號(hào)量控制的方式多進(jìn)入該臨界代碼(線程數(shù)量-1)次- (void)sellIphoneWithSynchronization{while(1) {@synchronized(self) {if(self.iphoneNumber >0)// 檢查還有沒(méi)iphone可賣(mài){NSLog(@"%@賣(mài)出iphone剩下%d臺(tái)iphone",[NSThreadcurrentThread].name,--self.iphoneNumber);? ? ? ? ? ? }else{NSLog(@"iphone沒(méi)有庫(kù)存了");return;? ? ? ? ? ? }? ? ? ? }? ? }}@end

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

三沪悲、控制同一個(gè)信號(hào)量(臨界資源)下的相關(guān)線程最大的并發(fā)數(shù)

////? 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這個(gè)信號(hào)量的相關(guān)線程最多幾個(gè)線程并發(fā)運(yùn)行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

下面是兩個(gè)現(xiàn)實(shí)生活的例子

一获洲、這是關(guān)于公交車(chē)上司機(jī)和售票員的配合問(wèn)題。

1.司機(jī)需要等待售票員關(guān)門(mén)后才能開(kāi)車(chē)

2.售票員需要等待司機(jī)停車(chē)后才能開(kāi)門(mén)

// 司機(jī)是否停車(chē)的信號(hào)量殿如,dispatch_semaphore_t semaphoreStopBused = dispatch_semaphore_create(1);// 售票員是否關(guān)門(mén)的信號(hào)量dispatch_semaphore_t semaphoreCloseDoored = dispatch_semaphore_create(0);// 拿到全局隊(duì)列dispatch_queue_tquene = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);// 司機(jī)的相關(guān)操作dispatch_async(quene, ^{while(1) {// 司機(jī)等待售票員關(guān)門(mén),DISPATCH_TIME_FOREVER表示這個(gè)信號(hào)量如果是0就一直等待這個(gè)信號(hào)量dispatch_semaphore_wait(semaphoreCloseDoored, DISPATCH_TIME_FOREVER);NSLog(@"司機(jī)開(kāi)車(chē)");NSLog(@"司機(jī)停車(chē)");// 司機(jī)已關(guān)門(mén)贡珊,停車(chē)的信號(hào)量加一dispatch_semaphore_signal(semaphoreStopBused);? ? ? ? }? ? });// 售票員的相關(guān)操作dispatch_async(quene, ^{while(1) {// 售票員等待司機(jī)停車(chē)dispatch_semaphore_wait(semaphoreStopBused, DISPATCH_TIME_FOREVER);NSLog(@"售票員開(kāi)門(mén)");NSLog(@"售票員關(guān)門(mén)");// 售票員已經(jīng)關(guān)門(mén)最爬,關(guān)門(mén)的信號(hào)量加一dispatch_semaphore_signal(semaphoreCloseDoored);? ? ? ? }? ? });

注意:

1.semaphoreStopBused和semaphoreCloseDoored信號(hào)量只能同時(shí)有一個(gè)是1,這值表示當(dāng)前是停車(chē)了還是關(guān)門(mén)了门岔,會(huì)觸發(fā)相關(guān)的流程

2.讓semaphoreCloseDoored為1爱致,semaphoreStopBused為0試試,觀察最開(kāi)始的流程走的順序有什么不同

二寒随、生產(chǎn)和銷(xiāo)售的問(wèn)題

/*

生產(chǎn)和銷(xiāo)售的線程同時(shí)操縱iphoneNumber變量為了保證數(shù)據(jù)的正確性糠悯,并且生產(chǎn)到5臺(tái)iphone就不再生產(chǎn)了。

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

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

上面圖的結(jié)果是正確的妻往,生產(chǎn)和銷(xiāo)售后的數(shù)據(jù)都能對(duì)的上栈幸。

如果把代碼更改為下面的情況瘫镇,就是不用信號(hào)量去做互斥的話,看下圖生成的錯(cuò)誤結(jié)果圖

/*

生產(chǎn)和銷(xiāo)售的互斥保證得到的數(shù)據(jù)是正確的宇弛,并且生產(chǎn)到5臺(tái)iphone就不再生產(chǎn)了

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

看下圖生成的錯(cuò)誤結(jié)果圖

圖片.png

上圖的結(jié)果有兩處錯(cuò)誤

1.連續(xù)生產(chǎn)兩次iphone后產(chǎn)品的數(shù)量都是5默刚。

2.連續(xù)賣(mài)掉兩次iphone后產(chǎn)品的數(shù)量都是4翻具。

參考資料:

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末脱拼,一起剝皮案震驚了整個(gè)濱河市裳仆,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌晦墙,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件肴茄,死亡現(xiàn)場(chǎng)離奇詭異晌畅,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)寡痰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門(mén)抗楔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人拦坠,你說(shuō)我怎么就攤上這事连躏。” “怎么了贞滨?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵入热,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我晓铆,道長(zhǎng)勺良,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任骄噪,我火速辦了婚禮尚困,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘链蕊。我一直安慰自己事甜,他們只是感情好谬泌,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著逻谦,像睡著了一般掌实。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上跨跨,一...
    開(kāi)封第一講書(shū)人閱讀 49,730評(píng)論 1 289
  • 那天潮峦,我揣著相機(jī)與錄音,去河邊找鬼勇婴。 笑死忱嘹,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的耕渴。 我是一名探鬼主播拘悦,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼橱脸!你這毒婦竟也來(lái)了础米?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤添诉,失蹤者是張志新(化名)和其女友劉穎屁桑,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體栏赴,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蘑斧,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了须眷。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片竖瘾。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖花颗,靈堂內(nèi)的尸體忽然破棺而出捕传,到底是詐尸還是另有隱情,我是刑警寧澤扩劝,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布庸论,位于F島的核電站,受9級(jí)特大地震影響棒呛,放射性物質(zhì)發(fā)生泄漏葡公。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一条霜、第九天 我趴在偏房一處隱蔽的房頂上張望催什。 院中可真熱鬧,春花似錦、人聲如沸蒲凶。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)旋圆。三九已至宠默,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間灵巧,已是汗流浹背搀矫。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留刻肄,地道東北人瓤球。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像敏弃,于是被迫代替她去往敵國(guó)和親卦羡。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容