iOS底層探索之多線程(十)—GCD源碼分析( 信號(hào)量dispatch_semaphore_t)

回顧

在上篇博客已經(jīng)對GCD柵欄函數(shù)做了一個(gè)基本介紹,還有應(yīng)用的舉例并且對底層源碼進(jìn)行了分析,本篇博客將對信號(hào)量進(jìn)行探索分析!

多線程

iOS底層探索之多線程(一)—進(jìn)程和線程

iOS底層探索之多線程(二)—線程和鎖

iOS底層探索之多線程(三)—初識(shí)GCD

iOS底層探索之多線程(四)—GCD的隊(duì)列

iOS底層探索之多線程(五)—GCD不同隊(duì)列源碼分析

iOS底層探索之多線程(六)—GCD源碼分析(sync 同步函數(shù)、async 異步函數(shù))

iOS底層探索之多線程(七)—GCD源碼分析(死鎖的原因)

iOS底層探索之多線程(八)—GCD源碼分析(函數(shù)的同步性、異步性、單例)

iOS底層探索之多線程(九)—GCD源碼分析(柵欄函數(shù))

1. 信號(hào)量

1.1 信號(hào)量介紹

信號(hào)量在GCD中是指Dispatch Semaphore,是一種持有計(jì)數(shù)的信號(hào)的東西。有如下三個(gè)方法。

  • dispatch_semaphore_create : 創(chuàng)建信號(hào)量
  • dispatch_semaphore_wait : 信號(hào)量等待
  • dispatch_semaphore_signal : 信號(hào)量釋放

1.2 信號(hào)量舉例

在并發(fā)隊(duì)列里面,可以使用信號(hào)量控制,最大并發(fā)數(shù),如下代碼:


信號(hào)量舉例
  • 信號(hào)量舉例打印結(jié)果
舉例結(jié)果.gif

這里一共創(chuàng)建了 4 個(gè)任務(wù),異步并發(fā)執(zhí)行,我在創(chuàng)建信號(hào)量的時(shí)候,設(shè)置了最大并發(fā)數(shù)為2

  dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_semaphore_t sem = dispatch_semaphore_create(2);

從運(yùn)行的動(dòng)圖,可以看到,每次都是兩個(gè)任務(wù)一起執(zhí)行了,打印的結(jié)果一目了然。

那么再舉個(gè)例子看看,設(shè)置信號(hào)量并發(fā)數(shù)為0

設(shè)置信號(hào)量并發(fā)數(shù)為0

設(shè)置信號(hào)量并發(fā)數(shù)為0,就相當(dāng)于加鎖的作用,dispatch_semaphore_wait堵住了任務(wù)1讓其等待,等任務(wù) 2執(zhí)行完了,dispatch_semaphore_signal發(fā)送信號(hào),我執(zhí)行完了,你去執(zhí)行吧!

這樣到底信號(hào)量是怎么樣等待,又是怎么樣發(fā)送信號(hào)的呢?

2. 信號(hào)量分析

看看dispatch_semaphore_createapi的說明

dispatch_semaphore_create

  • 當(dāng)兩個(gè)線程需要協(xié)調(diào)特定事件的完成時(shí),為該值傳遞0很有用。
  • 傳遞大于0的值對于管理有限的資源池很有用,其中池大小等于該值。
  • 信號(hào)量的起始值。 傳遞小于信號(hào)量的起始值。 傳遞小于零的值將導(dǎo)致返回 NULL。的值將導(dǎo)致返回 NULL,也就是小于0就不會(huì)正常執(zhí)行。

總結(jié)來說,就是可以控制線程池中的最多并發(fā)數(shù)量

2.1 dispatch_semaphore_signal

  • dispatch_semaphore_signal
dispatch_semaphore_signal
  • dispatch_semaphore_signal里面os_atomic_inc2o原子操作自增加1,然后會(huì)判斷,如果value > 0,就會(huì)返回0
  • 例如 value1之后還是小于0,說明是一個(gè)負(fù)數(shù),也就是調(diào)用dispatch_semaphore_wait次數(shù)太多了,dispatch_semaphore_wait是做減操作的,等會(huì)后面會(huì)分析。
  • 加一次后依然小于0就報(bào)異常"Unbalanced call to dispatch_semaphore_signal(),然后會(huì)調(diào)用_dispatch_semaphore_signal_slow方法的,做容錯(cuò)的處理,_dispatch_sema4_signal是一個(gè)do while 循環(huán)
_dispatch_semaphore_signal_slow(dispatch_semaphore_t dsema)
{
    _dispatch_sema4_create(&dsema->dsema_sema, _DSEMA4_POLICY_FIFO);
    _dispatch_sema4_signal(&dsema->dsema_sema, 1);
    return 1;
}
  • _dispatch_sema4_signal
void
_dispatch_sema4_signal(_dispatch_sema4_t *sema, long count)
{
    do {
        int ret = sem_post(sema);
        DISPATCH_SEMAPHORE_VERIFY_RET(ret);
    } while (--count);
}

2.2 dispatch_semaphore_wait

  • dispatch_semaphore_wait

dispatch_semaphore_wait源碼如下:

dispatch_semaphore_wait

  • os_atomic_dec2o進(jìn)行原子自減1操作,也就是對value值進(jìn)行減操作,控制可并發(fā)數(shù)。
  • 如果可并發(fā)數(shù)為2,則調(diào)用該方法后,變?yōu)?code>1,表示現(xiàn)在并發(fā)數(shù)為 1,剩下還可同時(shí)執(zhí)行1個(gè)任務(wù)。如果初始值是0,減操作之后為負(fù)數(shù),則會(huì)調(diào)用_dispatch_semaphore_wait_slow方法。

_dispatch_semaphore_wait_slow方法源碼如下:

  • _dispatch_semaphore_wait_slow
_dispatch_semaphore_wait_slow
  • 這里對dispatch_time_t timeout 進(jìn)行判斷處理,我們前面的例子里面?zhèn)鞯氖?code>DISPATCH_TIME_FOREVER,那么會(huì)調(diào)用_dispatch_sema4_wait方法
void
_dispatch_sema4_wait(_dispatch_sema4_t *sema)
{
    kern_return_t kr;
    do {
        kr = semaphore_wait(*sema);
    } while (kr == KERN_ABORTED);
    DISPATCH_SEMAPHORE_VERIFY_KR(kr);
}

_dispatch_sema4_wait方法里面是一個(gè)do-while循環(huán),當(dāng)不滿足條件時(shí),會(huì)一直循環(huán)下去,從而導(dǎo)致流程的阻塞。這也就解釋了上面舉例案里面的執(zhí)行結(jié)果。

上面舉例里面就相當(dāng)于,下圖中的情況

分析

在上圖框框的地方,① 相當(dāng)于②,這里是do-while循環(huán),所有會(huì)執(zhí)行任務(wù) 2,任務(wù) 1一直在循環(huán)等待。

3. 總結(jié)

  • dispatch_semaphore_wait 信號(hào)量等待,內(nèi)部是對并發(fā)數(shù)做自減操作,如果為 小于0,會(huì)執(zhí)行_dispatch_semaphore_wait_slow然后調(diào)用_dispatch_sema4_wait是一個(gè)do-while,知道滿足條件結(jié)束循環(huán)
  • dispatch_semaphore_signal 信號(hào)量釋放 ,內(nèi)部是對并發(fā)數(shù)做自加操作,直到大于0時(shí),為可操作
  • 保持線程同步,將異步執(zhí)行任務(wù)轉(zhuǎn)換為同步執(zhí)行任務(wù)
  • 保證線程安全,為線程加鎖,相當(dāng)于自旋鎖

更多內(nèi)容持續(xù)更新

?? 喜歡就點(diǎn)個(gè)贊吧????

?? 覺得有收獲的,可以來一波,收藏+關(guān)注,評(píng)論 + 轉(zhuǎn)發(fā),以免你下次找不到我????

??歡迎大家留言交流,批評(píng)指正,互相學(xué)習(xí)??,提升自我??

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容