民房做酒店出租網(wǎng)站app南寧seo推廣外包
???🌈大家好!本篇文章主要整理了部分多線程相關(guān)的內(nèi)容重點(diǎn)😇。首先講解了多進(jìn)程和多線程并發(fā)的區(qū)別以及各自優(yōu)缺點(diǎn),之后講解了Thead
線程庫(kù)的基本使用。
本專欄知識(shí)點(diǎn)是通過<零聲教育
>的音視頻流媒體高級(jí)開發(fā)
課程進(jìn)行系統(tǒng)學(xué)習(xí),梳理總結(jié)后寫下文章,對(duì)音視頻相關(guān)內(nèi)容感興趣的讀者,可以點(diǎn)擊觀看課程網(wǎng)址:零聲教育
🎡導(dǎo)航小助手🎡
- 一、多進(jìn)程與多線程
- 二、Thead線程庫(kù)的基本使用
- 三、小結(jié)
一、多進(jìn)程與多線程
首先有一個(gè)直觀的理解:
??1.進(jìn)程就是運(yùn)行中的程序
??2.線程就是進(jìn)程中的進(jìn)程
操作系統(tǒng)中可以有多個(gè)進(jìn)程,一個(gè)進(jìn)程中也可以有多個(gè)線程。
1.1 多線程并發(fā)
多進(jìn)程并發(fā)是將一個(gè)應(yīng)用程序劃分為多個(gè)獨(dú)立的進(jìn)程(每個(gè)進(jìn)程只有一個(gè)線程),這些獨(dú)立的進(jìn)程之間相互可以通信,共同完成任務(wù)。操作系統(tǒng)常常對(duì)進(jìn)程提供大量的保護(hù)機(jī)制,避免出現(xiàn)一個(gè)進(jìn)程修改其他進(jìn)程的數(shù)據(jù),因此,相對(duì)于多線程,使用多進(jìn)程更容易寫出相對(duì)安全的代碼。但這也造成了多進(jìn)程并發(fā)存在兩個(gè)不足之處:
- 進(jìn)程間的通信,無(wú)論是使用信號(hào)、套接字、還是文件、管道等方式,其使用要么比較復(fù)雜,要么就是速度較慢或者兩者兼而有之。
- 運(yùn)行多個(gè)線程,需要操作系統(tǒng)花費(fèi)很多資源進(jìn)行管理。
在多個(gè)進(jìn)程并發(fā)完成一個(gè)任務(wù)時(shí),常會(huì)出現(xiàn)操作同一個(gè)數(shù)據(jù)以及進(jìn)程之間的相互通信,因此,多進(jìn)程并發(fā)不是一個(gè)很好的選擇。
1.2 多線程并發(fā)
多線程并發(fā):同一個(gè)進(jìn)程中執(zhí)行多個(gè)線程。
- 優(yōu)點(diǎn):線程是輕量級(jí)的進(jìn)程,每個(gè)線程可以獨(dú)立的運(yùn)行不同的指令序列,且線程不獨(dú)立擁有資源,依賴于創(chuàng)建它的進(jìn)程而存在。
同一進(jìn)程中的多個(gè)線程能夠很方便的進(jìn)行數(shù)據(jù)共享以及通信,比進(jìn)程更適用于并發(fā)操作。
不足:缺少操作系統(tǒng)提供的保護(hù)機(jī)制。在多線程共享數(shù)據(jù)及通信時(shí),需程序員做更多的操作,并且還需極力避免死鎖。
二、Thead線程庫(kù)的基本使用
2.1 創(chuàng)建線程
要?jiǎng)?chuàng)建線程,我們需要一個(gè)可調(diào)用的函數(shù)或函數(shù)對(duì)象,作為線程的入口點(diǎn)。
在C++11中,我們可以使用函數(shù)指針、函數(shù)對(duì)象或lambda表達(dá)式
來實(shí)現(xiàn)。
創(chuàng)建線程的基本語(yǔ)法如下:
#include <thread>std::thread t(function_name, args...);
function_name
是線程入口點(diǎn)的函數(shù)或可調(diào)用對(duì)象args...
是傳遞給函數(shù)的參數(shù)
創(chuàng)建線程后,我們可以使用t.join()
等待線程完成,或者使用t.detach()
分離線程,讓它在后臺(tái)運(yùn)行。
實(shí)例1:
#include <iostream>#include <thread>using namespace std;void doit() { cout << "World!" << endl; }int main() {thread a([] {cout << "Hello, " << flush;}), b(doit);a.join();b.join();return 0;}
運(yùn)行結(jié)果:
上面兩次結(jié)果并不相同,這是因?yàn)槎嗑€程運(yùn)行時(shí)是以異步方式執(zhí)行的,與我們平時(shí)寫的同步方式不同。異步方式可以同時(shí)執(zhí)行多條語(yǔ)句,誰(shuí)先執(zhí)行得快,誰(shuí)先執(zhí)行完。
實(shí)例2:
#include <iostream>#include <thread>using namespace std;void thread_1(){cout<<"線程t"<<endl;}void print_message(const string& message) { cout << message <<endl;cout << "線程 t" << endl;}void increment(int& x) { ++x;cout << "線程 t2" << endl;}int main() { cout << "主線程1\n";thread t(thread_1);// 開啟線程t,調(diào)用:thread_1()t.join();cout << "子線程t結(jié)束\n";string message = "Hello, world!"; thread t1(print_message, message);// 開啟線程t1,調(diào)用:print_message()t1.join(); int x = 0; thread t2(increment, ref(x));//開啟線程t1,調(diào)用:increment() t2.join(); cout << "子線程t2結(jié)束\n";cout << x << endl; cout << "全部子進(jìn)程結(jié)束\n";return 0;}
運(yùn)行結(jié)果:
從上面結(jié)果,我們很明顯能看出,使用t.join()
后程序需要等待進(jìn)程t
結(jié)束后,才會(huì)接著進(jìn)行。
注意:thread在傳遞參數(shù)時(shí),是以右值傳遞的。
我們?cè)?strong>傳遞引用的時(shí)候,需要用到std::ref和std::cref
std::ref
可以包裝按引用傳遞的值。std::cref
可以包裝按const引用傳遞的值。
2.2 join與detach方式
當(dāng)線程啟動(dòng)后,一定要在和線程相關(guān)聯(lián)的thread
銷毀前,確定以何種方式等待線程執(zhí)行結(jié)束。比如上
例中的join。
? detach
方式,啟動(dòng)的線程自主在后臺(tái)運(yùn)行,當(dāng)前的代碼繼續(xù)往下執(zhí)行,不等待新線程結(jié)束。
? join
方式,等待啟動(dòng)的線程完成,才會(huì)繼續(xù)往下執(zhí)行。
可以使用joinable
判斷是join
模式還是detach
模式。
示例1:join舉例
#include <iostream>#include <thread>using namespace std;void thread_1() {while (1) {cout<<"子線程1"<<endl;}}void thread_2(int x) {while (1) {cout<<"子線程2"<<endl;}}int main() {thread first(thread_1);// 開啟線程,調(diào)用:thread_1()thread second(thread_2, 100);// 開啟線程,調(diào)用:thread_2(100)first.join(); // pauses until first finishes 這個(gè)操作完了之后才能destroyedsecond.join(); // pauses until second finishes//join完了之后,才能往下執(zhí)行。while (1) {std::cout << "主線程\n";}return 0;}
線程1和線程2寫的是死循環(huán),那么在兩個(gè)子線程沒結(jié)束前,主線程不會(huì)執(zhí)行。
示例2:detach舉例
#include <iostream>#include <thread>using namespace std;void thread_1() {while (1) {cout<<"子線程1"<<endl;}}void thread_2(int x) {while (1) {cout<<"子線程2"<<endl;}}int main() {thread first(thread_1);// 開啟線程,調(diào)用:thread_1()thread second(thread_2, 100);// 開啟線程,調(diào)用:thread_2(100)first.join(); // pauses until first finishes 這個(gè)操作完了之后才能destroyedsecond.join(); // pauses until second finishes//join完了之后,才能往下執(zhí)行。while (1) {std::cout << "主線程\n";}return 0;}
運(yùn)行結(jié)果:
可以看出,主線程不會(huì)等待子線程1和2結(jié)束。如果主線程運(yùn)行結(jié)束,程序則結(jié)束。
2.3 joinable
joinable()返回一個(gè)bool
值,判斷是join模式還是detach模式。
使用方法;
if (myThread.joinable()) 1 foo.join();
三、小結(jié)
- 多進(jìn)程安全但是浪費(fèi)操作系統(tǒng)資源且進(jìn)程間相互通信比較麻煩。多線程則可以很好的處理這兩個(gè)問題,但是使用時(shí)需要使用更多操作確保安全。
- C++11提供了語(yǔ)言層面上的多線程,包含在頭文件中。它解決了跨平臺(tái)的問題,提供了管理線程、保護(hù)共享數(shù)據(jù)、線程間同步操作、原子操作等類。主要講解了Thead線程庫(kù)的基本使用,包括join()、joinable()和detach(),并舉了很多例子進(jìn)行補(bǔ)充。
感謝大家閱讀!
接下來還會(huì)繼續(xù)更新多線程相關(guān)知識(shí),感興趣的可以看其他筆記!