由淺至深理解iOS GCD (一) -- Semaphore的基本概念和使用

前言:

本系列會(huì)由淺至深的講解iOS Dispatch的用法和實(shí)現(xiàn)原理,從最基本的概念到使用方法碘裕,再到實(shí)現(xiàn)原理攻锰,有時(shí)也會(huì)自己動(dòng)手實(shí)現(xiàn)其中的某些功能英岭。在講到一些基本概念和API介紹時(shí)荆烈,我會(huì)盡量用Apple的官方文檔來(lái)解釋昂儒,我認(rèn)為這樣最為準(zhǔn)確病涨,如果有已經(jīng)看過(guò)Apple文檔的同學(xué)可以跳步這個(gè)部分啰扛,直接看擴(kuò)展部分。

Dispatch Semaphore

單從字面上理解就是信號(hào)量的意思馆揉,他主要的作用在于處理多線程任務(wù)資源訪問(wèn)的問(wèn)題,我有時(shí)候也用于上鎖和解鎖的問(wèn)題抖拦。以下附上Apple的官方解釋:

You can use a dispatch semaphore to regulate the number of tasks allowed to simultaneously access a finite resource. For example, each application is given a limited number of file descriptors to use. If you have a task that processes large numbers of files, you do not want to open so many files at one time that you run out of file descriptors. Instead, you can use a semaphore to limit the number of file descriptors in use at any one time by your file-processing code.

你可以使用dispatch semaphore來(lái)調(diào)節(jié)同時(shí)訪問(wèn)有限資源的任務(wù)個(gè)數(shù)升酣。比如,沒(méi)有程序只能使用有限數(shù)量的文件描述符(fd)态罪。如果你有一個(gè)任務(wù)需要處理大量的文件噩茄,但是你又不想同時(shí)打開(kāi)太多的文件而耗盡fd,這時(shí)你就可以在你的文件處理代碼中用semaphore來(lái)限制使用fd的個(gè)數(shù)复颈。

A dispatch semaphore works like a traditional semaphore, except that when the resource is available, it takes less time to acquire a dispatch semaphore. The reason is that Grand Central Dispatch does not call into the kernel for this particular case. It calls into the kernel only when the resource is not available and the system needs to park your thread until the semaphore is signaled.

Dispatch semaphore和傳統(tǒng)信號(hào)量工作原理類(lèi)似绩聘。但是在資源可用的情況下,使用GCD semaphore將會(huì)消耗較少的時(shí)間耗啦,因?yàn)樵谶@種情況下GCD不會(huì)調(diào)用內(nèi)核凿菩,只有在資源不可用的時(shí)候才會(huì)調(diào)用內(nèi)核,并且系統(tǒng)需要停在你的線程里帜讲,直到發(fā)出這個(gè)信號(hào)衅谷。

GCD Semaphore的API介紹

dispatch_semaphore_create
dispatch_semaphore_t dispatch_semaphore_create(long value);

Creates new counting semaphore with an initial value.
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.
When your application no longer needs the semaphore, it should call dispatch_release to release its reference to the semaphore object and ultimately free its memory.

創(chuàng)建一個(gè)具有初始值的計(jì)數(shù)信號(hào)量。如果你有兩個(gè)線程共同完成某一項(xiàng)工作時(shí)似将,你可以使用一個(gè)初始值為0的semaphore获黔。如果你需要管理一個(gè)有限的資源池時(shí)蚀苛,你使用一個(gè)初始值為資源池的大小的Semaphore。如果你不在使用這個(gè)Semaphore時(shí)玷氏,你應(yīng)該使用dispatch_release銷(xiāo)毀semaphore對(duì)象并且釋放他的內(nèi)存堵未。(在ARC模式下不需要,系統(tǒng)會(huì)自動(dòng)釋放)

Parameters

value:
The starting value for the semaphore. Do not pass a value less than zero.

信號(hào)量的起始值盏触,必須傳一個(gè)大于等于0的值渗蟹,否則返回NULL對(duì)象。

Return

The newly created semaphore, or NULL on failure.

dispatch_semaphore_wait
long dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout);

Waits for (decrements) a semaphore.
Decrement the counting semaphore. If the resulting value is less than zero, this function waits for a signal to occur before returning.

等待一個(gè)semaphore耻陕,或者是減少semaphore的計(jì)數(shù)拙徽。每次會(huì)執(zhí)行會(huì)將計(jì)數(shù)器-1.如果減完之后計(jì)數(shù)器小于0的話,會(huì)阻塞在當(dāng)前線程直到接收到信號(hào)诗宣。

Parameters

timeout:When to timeout (see dispatch_time). The constants DISPATCH_TIME_NOW and DISPATCH_TIME_FOREVER are available as a convenience.

設(shè)置超時(shí)膘怕,詳情見(jiàn)dispatch_time。也可以使用常量 DISPATCH_TIME_NOW 和 DISPATCH_TIME_FOREVER召庞。DISPATCH_TIME_NOW可以理解為非阻塞型的等待(就是不等待)岛心。DISPATCH_TIME_FOREVER就是會(huì)一直等待,直到收到信號(hào)篮灼。

Return

Returns zero on success, or non-zero if the timeout occurred.

返回0就是成功忘古,返回非0就是超時(shí)。

dispatch_semaphore_signal
long dispatch_semaphore_signal(dispatch_semaphore_t dsema);

Signals, or increments, a semaphore.
Increment the counting semaphore. If the previous value was less than zero, this function wakes a thread currently waiting in dispatch_semaphore_wait.

發(fā)送信號(hào)诅诱,或者增加一個(gè)信號(hào)量的計(jì)數(shù)髓堪。如果增加之前的值小于0,則將會(huì)喚起一個(gè)在dispatch_semaphore_wait中等待的線程娘荡。(如果有多個(gè)線程在等待干旁,iOS會(huì)根據(jù)線程的優(yōu)先級(jí)來(lái)判斷具體喚醒哪個(gè)線程)。

注意事項(xiàng):

Dispatch Semaphore的用法相對(duì)簡(jiǎn)單炮沐,只要注一點(diǎn)就可以了争群。就是如果semaphore正在wait狀態(tài),也就是正在執(zhí)行dispatch_semaphore_wait操作大年,這時(shí)釋放Semaphore的內(nèi)存會(huì)程序會(huì)Crash换薄。

GCD Semaphore 的使用

GCD Semaphore非常簡(jiǎn)單,很好理解也很好上手翔试。

案例 多線程處理文件描述符:

假如我們?cè)谠O(shè)計(jì)socket通信模塊或者是文件系統(tǒng)轻要,為了防止數(shù)據(jù)錯(cuò)亂,我們不允許多線程同時(shí)往一個(gè)socket或者一個(gè)文件里面寫(xiě)數(shù)據(jù)垦缅。所以我們使用Semaphore添加限制伦腐。

- (void)sendData:(dispatch_data_t)data overPipeline:(dispatch_io_t)pipeline callback:(void (^)(NSError *))callback
{
    if(!_semaphore){
      // 初始化信號(hào)量,
        _semaphore = dispatch_semaphore_create(1);
    }

    // 等待信號(hào)量
    dispatch_semaphore_wait(_semaphore, DISPATCH_TIME_FOREVER);

    dispatch_io_write(pipeline, 0, data, _writeQueue, ^(bool done, dispatch_data_t data, int _errno){

      // 寫(xiě)完了失都,發(fā)送信號(hào)讓下一個(gè)等待的線程進(jìn)行寫(xiě)的操作柏蘑。
        dispatch_semaphore_signal(_semaphore);

        if (done && callback){
            callback(_errno == 0 ? nil : [[NSError alloc] initWithDomain:NSPOSIXErrorDomain code:_errno userInfo:nil]);
        }
    });
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末幸冻,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子咳焚,更是在濱河造成了極大的恐慌洽损,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,718評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件革半,死亡現(xiàn)場(chǎng)離奇詭異碑定,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)又官,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)延刘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人六敬,你說(shuō)我怎么就攤上這事碘赖。” “怎么了外构?”我有些...
    開(kāi)封第一講書(shū)人閱讀 158,207評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵普泡,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我审编,道長(zhǎng)撼班,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,755評(píng)論 1 284
  • 正文 為了忘掉前任垒酬,我火速辦了婚禮砰嘁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘勘究。我一直安慰自己般码,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,862評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布乱顾。 她就那樣靜靜地躺著,像睡著了一般宫静。 火紅的嫁衣襯著肌膚如雪走净。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 50,050評(píng)論 1 291
  • 那天孤里,我揣著相機(jī)與錄音伏伯,去河邊找鬼。 笑死捌袜,一個(gè)胖子當(dāng)著我的面吹牛说搅,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播虏等,決...
    沈念sama閱讀 39,136評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼弄唧,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼适肠!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起候引,我...
    開(kāi)封第一講書(shū)人閱讀 37,882評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤侯养,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后澄干,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體逛揩,經(jīng)...
    沈念sama閱讀 44,330評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,651評(píng)論 2 327
  • 正文 我和宋清朗相戀三年麸俘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了辩稽。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,789評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡从媚,死狀恐怖逞泄,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情静檬,我是刑警寧澤炭懊,帶...
    沈念sama閱讀 34,477評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站拂檩,受9級(jí)特大地震影響侮腹,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜稻励,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,135評(píng)論 3 317
  • 文/蒙蒙 一父阻、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧望抽,春花似錦加矛、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,864評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至辑奈,卻和暖如春苛茂,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背鸠窗。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,099評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工妓羊, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人稍计。 一個(gè)月前我還...
    沈念sama閱讀 46,598評(píng)論 2 362
  • 正文 我出身青樓躁绸,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子净刮,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,697評(píng)論 2 351

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

  • 。弹灭。
    Hi杰哥閱讀 112評(píng)論 0 1
  • 圖書(shū)館督暂,她坐在窗邊,兩扇窗子半開(kāi)著穷吮,窗外的柳樹(shù)枝丫逻翁,乘著風(fēng)微微搖擺,偶有一縷微風(fēng)穿過(guò)枝丫縫隙闖入窗內(nèi)捡鱼,惹得發(fā)梢歡快...
    彤彤妹閱讀 121評(píng)論 0 0
  • A1 小孩已經(jīng)9歲了八回,昨天跳舞回來(lái)將換下來(lái)的衣服裝在書(shū)包里,忘記拿出來(lái)洗了驾诈,今天外婆發(fā)現(xiàn)了就發(fā)火吵她說(shuō):“你...
    背包不知圓閱讀 179評(píng)論 0 0
  • 游戲乍迄,學(xué)習(xí)的真諦是及時(shí)反饋與矯正管引。 地圖學(xué)習(xí)的別稱是整體學(xué)習(xí)。 游戲?qū)W習(xí)闯两,意味著褥伴,從心里來(lái)說(shuō)。是一種主動(dòng)學(xué)習(xí)漾狼。主動(dòng)...
    躲進(jìn)小樓看燈火閱讀 469評(píng)論 0 0