C++ 線程(串行 并行 同步 異步)詳解
C++ 線程(串行 并行 同步 異步)詳解
看了很多關(guān)于這類的文章,一直沒有總結(jié)。不總結(jié)的話就會(huì)一直糊里糊涂,以下描述都是自己理解的非官方語言,不一定嚴(yán)謹(jǐn),可當(dāng)作參考。
首先,進(jìn)程可理解成一個(gè)可執(zhí)行文件的執(zhí)行過程。在ios app上的話我們可以理解為我們的app的.ipa文件執(zhí)行過程也即app運(yùn)行過程。殺掉app進(jìn)程就殺掉了這個(gè)app在系統(tǒng)里運(yùn)行所占的內(nèi)存。
線程:線程是進(jìn)程的最小單位。一個(gè)進(jìn)程里至少有一個(gè)主線程。就是那個(gè)main thread。非常簡(jiǎn)單的app可能只需要一個(gè)主線程即UI線程。當(dāng)然大部分還是會(huì)有一些子線程的,比如如果你用了AFNetWorking,你的請(qǐng)求都是開辟了子線程。
關(guān)于串行,并行,同步,異步,我還是以下面代碼的方式做個(gè)說明。
首先button點(diǎn)擊事件運(yùn)行在主線程里,先是在主線程里做了打印了一句話,然后創(chuàng)建了一個(gè)串行或者并行的隊(duì)列,之后連續(xù)創(chuàng)建了3個(gè)同步或者異步的block任務(wù)放入此隊(duì)列中,最后再在主線程里打印一句話。
- (IBAction)serialSync:(id)sender { NSLog(@"start log in main thread"]); dispatch_queue_t myQueue = dispatch_queue_create("myQueue", NULL); for (NSInteger n = 0; n < 3; n++) { dispatch_sync(myQueue, ^{ for (NSInteger i = 0; i < 500000000; i++) { if (i == 0) { NSLog(@"串行同步任務(wù)%ld -> 開始%@",n,[NSThread currentThread]); } if (i == 499999999) { NSLog(@"串行同步任務(wù)%ld -> 完成",(long)n); } } }); } NSLog(@"阻塞我沒有?當(dāng)前線程%@",[NSThread currentThread]); } - (IBAction)serialAsync:(id)sender { NSLog(@"start log in main thread"]); dispatch_queue_t myQueue = dispatch_queue_create("myQueue", NULL);//創(chuàng)建一個(gè)串行隊(duì)列 for (NSInteger n = 0; n < 3; n++) { dispatch_async(myQueue, ^{ for (NSInteger i = 0; i < 500000000; i++) { if (i == 0) { NSLog(@"串行異步任務(wù)%ld -> 開始%@",n,[NSThread currentThread]); } if (i == 499999999) { NSLog(@"串行異步任務(wù)%ld -> 完成",(long)n); } } }); } NSLog(@"阻塞我沒有?當(dāng)前線程%@",[NSThread currentThread]); } - (IBAction)concurrentSync:(id)sender { NSLog(@"start log in main thread"]); dispatch_queue_t myQueue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT); for (NSInteger n = 0; n < 3; n++) { dispatch_sync(myQueue, ^{ for (NSInteger i = 0; i < 500000000; i++) { if (i == 0) { NSLog(@"并行同步任務(wù)%ld -> 開始%@",(long)n,[NSThread currentThread]); } if (i == 499999999) { NSLog(@"并行同步任務(wù)%ld -> 完成",(long)n); } } }); } NSLog(@"阻塞我沒有?當(dāng)前線程%@",[NSThread currentThread]); } - (IBAction)concurrentAsync:(id)sender { NSLog(@"start log in main thread"]); dispatch_queue_t myQueue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT); for (NSInteger n = 0; n < 3; n++) { dispatch_async(myQueue, ^{ for (NSInteger i = 0; i < 500000000; i++) { if (i == 0) { NSLog(@"并行異步任務(wù)%ld -> 開始%@",n,[NSThread currentThread]); } if (i == 499999999) { NSLog(@"并行異步任務(wù)%ld -> 完成",(long)n); } } }); } NSLog(@"阻塞我沒有?當(dāng)前線程%@",[NSThread currentThread]); }
最后的結(jié)果如圖:
其中我把第一句打印和最后一句打印用玫紅色表示,它們都運(yùn)行在當(dāng)前線程。
方框表示隊(duì)列,3個(gè)block任務(wù)分別為3種不同的顏色。
可以看出:
串行即上一個(gè)block任務(wù)執(zhí)行完畢下一個(gè)任務(wù)才加入到隊(duì)列中。
并行即其中的任務(wù)同時(shí)加入到隊(duì)列中。
從運(yùn)行結(jié)果來看
第一個(gè)圖只有一個(gè)主線程:
3個(gè)block都是同步即都阻塞當(dāng)前線程,所以最后那句打印的任務(wù)就在3個(gè)block運(yùn)行完之后。
3個(gè)block又是串行,所以一個(gè)一個(gè)運(yùn)行
第二個(gè)圖有2個(gè)線程即一個(gè)主線程一個(gè)子線程:
3個(gè)block都是異步,沒有任務(wù)阻塞當(dāng)前線程。所以最后那句打印是在第一句打印后就可以開始執(zhí)行的。
3個(gè)block都是異步,異步會(huì)創(chuàng)建新的線程即至少有一個(gè)子線程。
3個(gè)block是串行,只有一個(gè)任務(wù)做完才會(huì)加另一個(gè)任務(wù)入隊(duì)列,所以只需一個(gè)子線程。
第三個(gè)圖只有一個(gè)主線程:
3個(gè)block都是同步即都阻塞當(dāng)前線程,所以最后那句打印的任務(wù)就在3個(gè)block運(yùn)行完之后。
3個(gè)block是并行,同時(shí)被加入隊(duì)列中。
3個(gè)block都是同步,由于同步意味著等待,所以任務(wù)的執(zhí)行表現(xiàn)為順序執(zhí)行,其實(shí)是一起加進(jìn)去的但是等待的,跟串行的區(qū)別是串行是別的任務(wù)做完才把它加進(jìn)隊(duì)列中。
第四個(gè)圖有多個(gè)線程:
3個(gè)block都是異步,沒有任務(wù)阻塞當(dāng)前線程。所以最后那句打印是在第一句打印后就可以開始執(zhí)行的。
3個(gè)block都是異步,異步會(huì)創(chuàng)建新的線程即至少有一個(gè)子線程。
3個(gè)block是并行,需創(chuàng)建多個(gè)子線程才能保證任務(wù)同時(shí)執(zhí)行。
再看一張圖:其中第一個(gè)異步為玫紅色,兩個(gè)同步分別以紫色黃色表示,兩個(gè)異步分別以綠色棕色表示,隊(duì)列后面的當(dāng)前線程動(dòng)作為橘色。虛線代表等待。上面代表串行,下面是并行。
由此圖可以看出:
同步block會(huì)阻塞當(dāng)前線程,即會(huì)在當(dāng)前線程中運(yùn)行。(這里的當(dāng)前線程為主線程所以會(huì)看到UI卡住)
異步block會(huì)開辟新的線程。
在串行隊(duì)列中,異步block任務(wù)用的是同一個(gè)子線程,因?yàn)樾枰却蝿?wù)一個(gè)一個(gè)地執(zhí)行,不需要多個(gè)線程。
在并行隊(duì)列中,異步block任務(wù)同時(shí)執(zhí)行,系統(tǒng)為其分配線程。圖中的例子因第一個(gè)異步操作在第二個(gè)開始前已經(jīng)結(jié)束了,所以并不是多少個(gè)異步操作就創(chuàng)建多少線程,主要還是看需要。
感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!
相關(guān)文章
C語言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
這篇文章主要介紹了C語言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例,并且轉(zhuǎn)換后會(huì)統(tǒng)計(jì)二進(jìn)制1的個(gè)數(shù),實(shí)例簡(jiǎn)單明了,需要的朋友可以參考下2014-06-06win32下進(jìn)程間通信(共享內(nèi)存)實(shí)例分析
這篇文章主要介紹了win32下進(jìn)程間通信(共享內(nèi)存)實(shí)例分析,對(duì)win32應(yīng)用程序及進(jìn)程的原理做了較為深入的剖析,需要的朋友可以參考下2014-07-07SublimeText編譯C開發(fā)環(huán)境設(shè)置
這篇文章主要介紹了使用SublimeText編譯C代碼的開發(fā)環(huán)境設(shè)置,大家參考使用2013-11-11嵌入式C程序優(yōu)質(zhì)編寫全面教程規(guī)范
這是一年前我為公司內(nèi)部寫的一個(gè)文檔,旨在向年輕的嵌入式軟件工程師們介紹如何在裸機(jī)環(huán)境下編寫優(yōu)質(zhì)嵌入式C程序。感覺是有一定的參考價(jià)值,所以拿出來分享,拋磚引玉2022-04-04探究C++中指針與數(shù)組運(yùn)算符優(yōu)先級(jí)
C++中與指針和數(shù)組相關(guān)的運(yùn)算符優(yōu)先級(jí),通過實(shí)際代碼示例解釋了運(yùn)算符的左結(jié)合與右結(jié)合方式,以及如何使用圓括號(hào)()來改變默認(rèn)的結(jié)合順序,文章還提供了一個(gè)優(yōu)先級(jí)表,列出了運(yùn)算符的優(yōu)先級(jí)和結(jié)合性,幫助讀者更好地理解復(fù)雜表達(dá)式中運(yùn)算符的調(diào)用順序2024-10-10淺談C語言共用體和與結(jié)構(gòu)體的區(qū)別
下面小編就為大家?guī)硪黄獪\談C語言共用體和與結(jié)構(gòu)體的區(qū)別。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-02-02opencv利用鼠標(biāo)滑動(dòng)畫出多彩的形狀
這篇文章主要為大家詳細(xì)介紹了opencv利用鼠標(biāo)滑動(dòng)畫出多彩的形狀,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-07-07