信號(hào)量

1.信號(hào)量使用的情況

信號(hào)量一般用來(lái)進(jìn)行臨界訪(fǎng)問(wèn)或者互斥訪(fǎng)問(wèn)的。臨界資源可以理解為共享資源,這個(gè)共享資源每次每次只允許一個(gè)進(jìn)程進(jìn)行訪(fǎng)問(wèn),當(dāng)一個(gè)線(xiàn)程進(jìn)入后,其他線(xiàn)程是不允許訪(fǎng)問(wèn)這一塊資源的,只能等這一線(xiàn)程訪(fǎng)問(wèn)完后才能進(jìn)入訪(fǎng)問(wèn)。

2.P V操作

P V操作主要是為了對(duì)信號(hào)量進(jìn)行申請(qǐng)或者釋放。P操作表示申請(qǐng)一個(gè)資源,V操作表示釋放一個(gè)資源。信號(hào)量由一個(gè)值和一個(gè)指針組成,指針指向等待該信號(hào)量的進(jìn)程。信號(hào)量的值表示相應(yīng)資源的使用情況。當(dāng)信號(hào)量S>=0時(shí),S表示可用資源的數(shù)量。執(zhí)行P操作意味著請(qǐng)求資源,此時(shí)S減一,當(dāng)S<0時(shí),表示沒(méi)有可用的資源,此時(shí)S的絕對(duì)值表示當(dāng)前等待該資源的進(jìn)程數(shù)。這些進(jìn)程必須等資源被釋放后才能繼續(xù)運(yùn)行。而執(zhí)行V操作意味著釋放一個(gè)資源,S加1。

3.GCD中的信號(hào)量

GCD中有三個(gè)函數(shù)是semaphore的操作:
Dispatch_semaphore_create //創(chuàng)建一個(gè)信號(hào)量
Dispatch_semaphore_signal //發(fā)送一個(gè)信號(hào),讓信號(hào)量增加一
Dispatch_semaphore_wait //等待信號(hào),如果信號(hào)總量大于0,則減掉一個(gè)信號(hào)量

4.GCD中信號(hào)量的使用

(1)首先看一段并發(fā)的代碼

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        for (int i = 0; i < 10; i ++) {
            NSLog(@"第一組現(xiàn)在是%d",i);
        }
    });

    NSLog(@"現(xiàn)在我執(zhí)行了");
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        for (int i = 0; i < 10; i ++) {
            NSLog(@"第二組現(xiàn)在是%d",i);
        }
    });

輸出結(jié)果:

2017-03-01 15:01:43.714 信號(hào)量[6437:260451] 第一組現(xiàn)在是1
2017-03-01 15:01:43.714 信號(hào)量[6437:260466] 第二組現(xiàn)在是0
2017-03-01 15:01:43.714 信號(hào)量[6437:260466] 第二組現(xiàn)在是1
2017-03-01 15:01:43.714 信號(hào)量[6437:260451] 第一組現(xiàn)在是2
2017-03-01 15:01:43.714 信號(hào)量[6437:260466] 第二組現(xiàn)在是2
2017-03-01 15:01:43.714 信號(hào)量[6437:260451] 第一組現(xiàn)在是3
2017-03-01 15:01:43.714 信號(hào)量[6437:260466] 第二組現(xiàn)在是3
2017-03-01 15:01:43.715 信號(hào)量[6437:260451] 第一組現(xiàn)在是4
2017-03-01 15:01:43.715 信號(hào)量[6437:260466] 第二組現(xiàn)在是4
2017-03-01 15:01:43.715 信號(hào)量[6437:260451] 第一組現(xiàn)在是5
2017-03-01 15:01:43.715 信號(hào)量[6437:260466] 第二組現(xiàn)在是5
2017-03-01 15:01:43.715 信號(hào)量[6437:260451] 第一組現(xiàn)在是6
2017-03-01 15:01:43.715 信號(hào)量[6437:260466] 第二組現(xiàn)在是6
2017-03-01 15:01:43.715 信號(hào)量[6437:260451] 第一組現(xiàn)在是7
2017-03-01 15:01:43.715 信號(hào)量[6437:260466] 第二組現(xiàn)在是7
2017-03-01 15:01:43.715 信號(hào)量[6437:260451] 第一組現(xiàn)在是8
2017-03-01 15:01:43.715 信號(hào)量[6437:260466] 第二組現(xiàn)在是8
2017-03-01 15:01:43.715 信號(hào)量[6437:260451] 第一組現(xiàn)在是9
2017-03-01 15:01:43.716 信號(hào)量[6437:260466] 第二組現(xiàn)在是9

從上面的輸出結(jié)果來(lái)看這一段代碼是并發(fā)執(zhí)行的,第一組和第二組交替執(zhí)行。
關(guān)于進(jìn)程、線(xiàn)程的概念以及多線(xiàn)程可以參考我另一篇文章
iOS多線(xiàn)程的簡(jiǎn)介及使用(http://www.itdecent.cn/p/59da6f924e95

(2)那么現(xiàn)在我想上面的代碼第一組執(zhí)行完了再執(zhí)行第二段該怎么辦呢,下面我們加入信號(hào)量來(lái)試一下

    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(15.0 * NSEC_PER_SEC));
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        for (int i = 0; i < 10; i ++) {
            NSLog(@"第一組現(xiàn)在是%d",i);
        }
       dispatch_semaphore_signal(semaphore);
    });
    dispatch_semaphore_wait(semaphore, time);
    NSLog(@"現(xiàn)在我執(zhí)行了");
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        for (int i = 0; i < 10; i ++) {
            NSLog(@"第二組現(xiàn)在是%d",i);
        }
});

輸出結(jié)果:

2017-03-01 15:08:37.848 信號(hào)量[6577:266811] 第一組現(xiàn)在是0
2017-03-01 15:08:37.848 信號(hào)量[6577:266811] 第一組現(xiàn)在是1
2017-03-01 15:08:37.848 信號(hào)量[6577:266811] 第一組現(xiàn)在是2
2017-03-01 15:08:37.848 信號(hào)量[6577:266811] 第一組現(xiàn)在是3
2017-03-01 15:08:37.849 信號(hào)量[6577:266811] 第一組現(xiàn)在是4
2017-03-01 15:08:37.849 信號(hào)量[6577:266811] 第一組現(xiàn)在是5
2017-03-01 15:08:37.849 信號(hào)量[6577:266811] 第一組現(xiàn)在是6
2017-03-01 15:08:37.849 信號(hào)量[6577:266811] 第一組現(xiàn)在是7
2017-03-01 15:08:37.849 信號(hào)量[6577:266811] 第一組現(xiàn)在是8
2017-03-01 15:08:37.850 信號(hào)量[6577:266811] 第一組現(xiàn)在是9
2017-03-01 15:08:37.850 信號(hào)量[6577:266778] 現(xiàn)在我執(zhí)行了
2017-03-01 15:08:37.850 信號(hào)量[6577:266811] 第二組現(xiàn)在是0
2017-03-01 15:08:37.850 信號(hào)量[6577:266811] 第二組現(xiàn)在是1
2017-03-01 15:08:37.850 信號(hào)量[6577:266811] 第二組現(xiàn)在是2
2017-03-01 15:08:37.851 信號(hào)量[6577:266811] 第二組現(xiàn)在是3
2017-03-01 15:08:37.851 信號(hào)量[6577:266811] 第二組現(xiàn)在是4
2017-03-01 15:08:37.851 信號(hào)量[6577:266811] 第二組現(xiàn)在是5
2017-03-01 15:08:37.851 信號(hào)量[6577:266811] 第二組現(xiàn)在是6
2017-03-01 15:08:37.851 信號(hào)量[6577:266811] 第二組現(xiàn)在是7
2017-03-01 15:08:37.852 信號(hào)量[6577:266811] 第二組現(xiàn)在是8
2017-03-01 15:08:37.852 信號(hào)量[6577:266811] 第二組現(xiàn)在是9

從上面的結(jié)果來(lái)看我們的代碼達(dá)到了我們預(yù)期的效果,那么我們來(lái)分析一下上面的代碼我們到底做了什么事情:
首先我們創(chuàng)建了一個(gè)信號(hào)量,這個(gè)信號(hào)量的初始值為0
然后我們?cè)O(shè)置了一個(gè)超時(shí)時(shí)間,在第一組的循環(huán)結(jié)束時(shí)我們釋放了信號(hào)量,即進(jìn)行了V操作,然后在第二組循環(huán)代碼前面我們進(jìn)行了P操作,請(qǐng)求了信號(hào)量我們的代碼相比上面的不同點(diǎn)之處是多了這4句代碼

代碼的不同之處分析完了,那么我們?cè)賮?lái)分析一下為什么會(huì)出現(xiàn)這種結(jié)果:
信號(hào)量的初始值為0,然后我們?cè)谝粋€(gè)并行隊(duì)列里面異步執(zhí)行一個(gè)for 循環(huán),因?yàn)槭钱惒?,所以我們可以直接往下面的代碼走,這是我們進(jìn)行了P操作,信號(hào)量要減一,因?yàn)樾盘?hào)量此時(shí)已經(jīng)為0,我們可以理解為沒(méi)有多余資源,此時(shí)要堵塞線(xiàn)程等待資源,然后等第一組的for循環(huán)執(zhí)行完畢之后,信號(hào)量被加1,此時(shí)有了資源,于是代碼繼續(xù)往下執(zhí)行,進(jìn)入第二組for循環(huán)。

(3)看到這里你是不是已經(jīng)認(rèn)為自己已經(jīng)掌握了信號(hào)量,覺(jué)得自己能獨(dú)步武林,笑傲江湖,年輕人 too young too simple我們?cè)賮?lái)看一段代碼:

    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(15.0 * NSEC_PER_SEC));
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        for (int i = 0; i < 10; i ++) {
            NSLog(@"第一組現(xiàn)在是%d",i);
             dispatch_semaphore_signal(semaphore);
        }
    });
    dispatch_semaphore_wait(semaphore, time);
    NSLog(@"現(xiàn)在我執(zhí)行了");
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        for (int i = 0; i < 10; i ++) {
            NSLog(@"第二組現(xiàn)在是%d",i);
        }
    });

輸出結(jié)果:

2017-03-01 15:34:02.068 信號(hào)量[7015:284862] 第一組現(xiàn)在是0
2017-03-01 15:34:02.069 信號(hào)量[7015:284862] 第一組現(xiàn)在是1
2017-03-01 15:34:02.069 信號(hào)量[7015:284816] 現(xiàn)在我執(zhí)行了
2017-03-01 15:34:02.069 信號(hào)量[7015:284862] 第一組現(xiàn)在是2
2017-03-01 15:34:02.069 信號(hào)量[7015:284863] 第二組現(xiàn)在是0
2017-03-01 15:34:02.069 信號(hào)量[7015:284862] 第一組現(xiàn)在是3
2017-03-01 15:34:02.069 信號(hào)量[7015:284863] 第二組現(xiàn)在是1
2017-03-01 15:34:02.069 信號(hào)量[7015:284862] 第一組現(xiàn)在是4
2017-03-01 15:34:02.069 信號(hào)量[7015:284863] 第二組現(xiàn)在是2
2017-03-01 15:34:02.069 信號(hào)量[7015:284862] 第一組現(xiàn)在是5
2017-03-01 15:34:02.069 信號(hào)量[7015:284863] 第二組現(xiàn)在是3
2017-03-01 15:34:02.070 信號(hào)量[7015:284862] 第一組現(xiàn)在是6
2017-03-01 15:34:02.070 信號(hào)量[7015:284863] 第二組現(xiàn)在是4
2017-03-01 15:34:02.070 信號(hào)量[7015:284862] 第一組現(xiàn)在是7
2017-03-01 15:34:02.070 信號(hào)量[7015:284863] 第二組現(xiàn)在是5
2017-03-01 15:34:02.070 信號(hào)量[7015:284862] 第一組現(xiàn)在是8
2017-03-01 15:34:02.070 信號(hào)量[7015:284863] 第二組現(xiàn)在是6
2017-03-01 15:34:02.070 信號(hào)量[7015:284862] 第一組現(xiàn)在是9
2017-03-01 15:34:02.070 信號(hào)量[7015:284863] 第二組現(xiàn)在是7
2017-03-01 15:34:02.071 信號(hào)量[7015:284863] 第二組現(xiàn)在是8
2017-03-01 15:34:02.071 信號(hào)量[7015:284863] 第二組現(xiàn)在是9

看到這個(gè)輸出結(jié)果,有些人可能一臉懵逼,為什么,我覺(jué)得這代碼一樣啊,我們?cè)賮?lái)仔細(xì)看看這段代碼與上面的有什么不同,仔細(xì)看我們會(huì)發(fā)現(xiàn)唯一的不同點(diǎn)在于信號(hào)量的發(fā)送時(shí)間不同,即進(jìn)行V操作的時(shí)間不一樣,在上面的代碼里面我們是在for循環(huán)結(jié)束之后才進(jìn)行發(fā)送信號(hào)量的操作,但是在這里我們是每進(jìn)行一次for循環(huán)我們就發(fā)送一次信號(hào)量,這樣其實(shí)信號(hào)量一直在增加,于是第二個(gè)for 循環(huán)就不會(huì)被阻塞,就出現(xiàn)了我們看到的結(jié)果(其實(shí)這一塊第一組的0一定是先于現(xiàn)在我執(zhí)行了這句話(huà)執(zhí)行的,童鞋們可以多試一試看看是不是這種情況)

(4)我們?cè)賮?lái)看一種情況

    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(15.0 * NSEC_PER_SEC));
     dispatch_semaphore_wait(semaphore, time);
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        for (int i = 0; i < 10; i ++) {
            NSLog(@"第一組現(xiàn)在是%d",i);
        }
                  dispatch_semaphore_signal(semaphore);
    });
   
    NSLog(@"現(xiàn)在我執(zhí)行了");
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        for (int i = 0; i < 10; i ++) {
            NSLog(@"第二組現(xiàn)在是%d",i);
        }
    });

輸出結(jié)果:

2017-03-01 16:10:43.640 信號(hào)量[7549:307322] 第一組現(xiàn)在是0
2017-03-01 16:10:43.640 信號(hào)量[7549:307270] 現(xiàn)在我執(zhí)行了
2017-03-01 16:10:43.640 信號(hào)量[7549:307322] 第一組現(xiàn)在是1
2017-03-01 16:10:43.640 信號(hào)量[7549:307743] 第二組現(xiàn)在是0
2017-03-01 16:10:43.640 信號(hào)量[7549:307322] 第一組現(xiàn)在是2
2017-03-01 16:10:43.641 信號(hào)量[7549:307743] 第二組現(xiàn)在是1
2017-03-01 16:10:43.641 信號(hào)量[7549:307322] 第一組現(xiàn)在是3
2017-03-01 16:10:43.641 信號(hào)量[7549:307743] 第二組現(xiàn)在是2
2017-03-01 16:10:43.641 信號(hào)量[7549:307322] 第一組現(xiàn)在是4
2017-03-01 16:10:43.641 信號(hào)量[7549:307743] 第二組現(xiàn)在是3
2017-03-01 16:10:43.641 信號(hào)量[7549:307322] 第一組現(xiàn)在是5
2017-03-01 16:10:43.642 信號(hào)量[7549:307743] 第二組現(xiàn)在是4
2017-03-01 16:10:43.642 信號(hào)量[7549:307322] 第一組現(xiàn)在是6
2017-03-01 16:10:43.642 信號(hào)量[7549:307743] 第二組現(xiàn)在是5
2017-03-01 16:10:43.642 信號(hào)量[7549:307322] 第一組現(xiàn)在是7
2017-03-01 16:10:43.642 信號(hào)量[7549:307743] 第二組現(xiàn)在是6
2017-03-01 16:10:43.642 信號(hào)量[7549:307322] 第一組現(xiàn)在是8
2017-03-01 16:10:43.643 信號(hào)量[7549:307743] 第二組現(xiàn)在是7
2017-03-01 16:10:43.643 信號(hào)量[7549:307322] 第一組現(xiàn)在是9
2017-03-01 16:10:43.643 信號(hào)量[7549:307743] 第二組現(xiàn)在是8
2017-03-01 16:10:43.643 信號(hào)量[7549:307743] 第二組現(xiàn)在是9

從輸出結(jié)果上來(lái)看好像兩個(gè)for循環(huán)是并發(fā)執(zhí)行的,但是童鞋們可以跑一下這段代碼,你會(huì)發(fā)現(xiàn)程序運(yùn)行起來(lái)之后會(huì)等一段時(shí)間才會(huì)有輸出結(jié)果,這是為什么呢,因?yàn)閯傞_(kāi)始信號(hào)量是0,然后我們?cè)O(shè)置了一個(gè)超時(shí)時(shí)間,當(dāng)進(jìn)行P操作對(duì)信號(hào)量減一的時(shí)候會(huì)堵塞,因?yàn)闆](méi)有可用資源,等到超時(shí)時(shí)間過(guò)去程序才會(huì)繼續(xù)往下走。這就導(dǎo)致了我們前期有一段時(shí)間一直沒(méi)有輸出結(jié)果,其實(shí)是因?yàn)榫€(xiàn)程被堵塞了。

總結(jié):對(duì)信號(hào)量進(jìn)行P V操作一定要考慮清楚應(yīng)該在什么時(shí)候進(jìn)行,不然可能會(huì)達(dá)不到我們預(yù)期的效果,同時(shí)當(dāng)信號(hào)量為0的時(shí)候代碼是可以繼續(xù)往下執(zhí)行的,只要你不進(jìn)行P操作(有些博客上說(shuō)當(dāng)信號(hào)量為0 的時(shí)候就阻塞了,但我測(cè)試為0的時(shí)候代碼是可以往下執(zhí)行的,不知道是不是我理解的有偏差),當(dāng)被阻塞的時(shí)候,過(guò)了超時(shí)時(shí)間代碼也可以繼續(xù)往下執(zhí)行。以上就是我對(duì)信號(hào)量的初步理解,有什么不對(duì)的還要大家多指教,如果有什么好的關(guān)于信號(hào)量的博客大家也可以推薦一下,共同研究。

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

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,068評(píng)論 25 709
  • 信號(hào)與信號(hào)量是不同的兩種事物。 什么是信號(hào)量 為了防止出現(xiàn)因多個(gè)程序同時(shí)訪(fǎng)問(wèn)一個(gè)共享資源而引發(fā)的一系列問(wèn)題,我們需...
    lintong閱讀 3,884評(píng)論 0 8
  • 本文轉(zhuǎn)載自信號(hào)量與互斥鎖,如有侵權(quán),請(qǐng)及時(shí)聯(lián)系博主刪除。 1. 信號(hào)量與普通整型變量的區(qū)別: ①信號(hào)量(semap...
    GLGeek閱讀 1,306評(píng)論 0 1
  • 『施鳴的感激』第13天--《【啾啾”時(shí)間(13)】和施鳴體驗(yàn)的鏈接!》 感激者:施鳴 地點(diǎn):上海崇明 時(shí)間:201...
    施鳴閱讀 304評(píng)論 0 2
  • 最近有個(gè)同學(xué)因?yàn)楦髯约依锏囊恍┦虑椋?我們就聊起來(lái)。 我們不是很熟啊的時(shí)候。 我總覺(jué)得她是一個(gè)蠻成熟的人,好像很多...
    大靜不靜閱讀 321評(píng)論 0 0

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