信號(hào)量機(jī)制
在 iOS 系統(tǒng)及大部分現(xiàn)代操作系統(tǒng)中涩盾,多個(gè)線程可以并發(fā)執(zhí)行,CPU在線程之間來(lái)回切換励背,共享某些資源春霍,提高了資源的利用率。但是我們?cè)撊绾翁幚砀鱾€(gè)線程之間的相互制約關(guān)系叶眉?比如只有一臺(tái)打印機(jī)址儒,兩個(gè)線程都需要打印文件,如果直接讓他們簡(jiǎn)單的并發(fā)訪問(wèn)打印機(jī)衅疙,那么很可能什么都打印不出來(lái)或者打印的文件是混亂的莲趣。顯然,我們需要增加一種機(jī)制來(lái)控制線程間的相互制約關(guān)系炼蛤。
簡(jiǎn)單來(lái)說(shuō)就是我們需要一種機(jī)制來(lái)控制線程執(zhí)行的先后順序妖爷。
而信號(hào)量就可以提供這樣的一種機(jī)制,讓一個(gè)臨界區(qū)(臨界區(qū)指的是線程中訪問(wèn)共用資源的程序片段)同一時(shí)間只有一個(gè)線程在訪問(wèn)它,也就是說(shuō)信號(hào)量是用來(lái)協(xié)調(diào)線程對(duì)共享資源的訪問(wèn)的絮识。
信號(hào)量可以理解為是一個(gè)資源計(jì)數(shù)器绿聘,對(duì)信號(hào)量有兩個(gè)操作來(lái)達(dá)到互斥,分別是P和V操作次舌。 一般情況是這樣進(jìn)行臨界訪問(wèn)或互斥訪問(wèn)的: 設(shè)信號(hào)量值為1熄攘, 當(dāng)一個(gè)線程A運(yùn)行時(shí),使用資源彼念,進(jìn)行P操作挪圾,即對(duì)信號(hào)量值減1,也就是資源數(shù)少了1個(gè)逐沙。這時(shí)信號(hào)量值為0哲思。系統(tǒng)中規(guī)定當(dāng)信號(hào)量值為0是,必須等待吩案,直到信號(hào)量值不為零才能繼續(xù)操作棚赔。 這時(shí)如果線程B想要運(yùn)行,那么也必須進(jìn)行P操作徘郭,但是此時(shí)信號(hào)量為0靠益,所以無(wú)法減1,即不能P操作残揉,也就阻塞胧后。這樣就達(dá)到了線程A的排他訪問(wèn)。 當(dāng)線程A運(yùn)行結(jié)束后抱环,釋放資源壳快,進(jìn)行V操作。資源數(shù)重新加1江醇,這時(shí)信號(hào)量的值變?yōu)?濒憋,這時(shí)線程B發(fā)現(xiàn)資源數(shù)不為0,信號(hào)量能進(jìn)行P操作了陶夜,立即執(zhí)行P操作。信號(hào)量值又變?yōu)?裆站,線程B有資源条辟,其余線程必須等到,達(dá)到線程B的排他訪問(wèn)宏胯。 這就是信號(hào)量來(lái)控制線程互斥的原理羽嫡。
GCD如何使用信號(hào)量
在GCD中有三個(gè)函數(shù)是semaphore的操作,分別是:
dispatch_semaphore_create(long value); // 創(chuàng)建一個(gè)semaphore
dispatch_semaphore_signal(dispatch_semaphore_t dsema); // 發(fā)送一個(gè)信號(hào)
dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout); // 等到信號(hào)
第一個(gè)函數(shù)有一個(gè)長(zhǎng)整形的參數(shù)肩袍,我們可以理解為信號(hào)的總量杭棵,dispatch_semaphore_signal是發(fā)送一個(gè)信號(hào),自然會(huì)讓信號(hào)總量加1,dispatch_semaphore_wait等待信號(hào)魂爪,當(dāng)信號(hào)總量少于0的時(shí)候就會(huì)一直等待先舷,否則就可以正常的執(zhí)行,并讓信號(hào)總量-1滓侍,根據(jù)這樣的原理蒋川,我們便可以快速的創(chuàng)建一個(gè)并發(fā)控制來(lái)同步任務(wù)和有限資源訪問(wèn)控制。
// 創(chuàng)建隊(duì)列組
dispatch_group_t group = dispatch_group_create();
// 創(chuàng)建信號(hào)量撩笆,并且設(shè)置值為10
dispatch_semaphore_t semaphore = dispatch_semaphore_create(10);
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
for (int i = 0; i < 100; i++)
{ // 由于是異步執(zhí)行的捺球,所以每次循環(huán)Block里面的dispatch_semaphore_signal根本還沒(méi)有執(zhí)行就會(huì)執(zhí)行dispatch_semaphore_wait,從而semaphore-1.當(dāng)循環(huán)10此后夕冲,semaphore等于0氮兵,則會(huì)阻塞線程,直到執(zhí)行了Block的dispatch_semaphore_signal 才會(huì)繼續(xù)執(zhí)行
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_group_async(group, queue, ^{
NSLog(@"%i",i);
sleep(2);
// 每次發(fā)送信號(hào)則semaphore會(huì)+1歹鱼,
dispatch_semaphore_signal(semaphore);
});
}
總結(jié)
信號(hào)量是用在多線程并發(fā)的泣栈,一個(gè)線程完成了某一個(gè)動(dòng)作就通過(guò)信號(hào)量告訴別的線程,別的線程再進(jìn)行某些動(dòng)作醉冤。
參考鏈接
1.信號(hào)量與鎖的差別
2.淺談GCD中的信號(hào)量
3.用信號(hào)量解決進(jìn)程的同步與互斥探討
內(nèi)容整理自網(wǎng)絡(luò)秩霍,如有侵權(quán)請(qǐng)聯(lián)系刪除。
聯(lián)系作者:簡(jiǎn)書·DH_Fantasy 新浪微博·DH_Fantasy
版權(quán)聲明:自由轉(zhuǎn)載-非商用-非衍生-保持署名(CC BY-NC-ND 3.0)