亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

C++初級(jí)線程管理

 更新時(shí)間:2021年12月24日 11:27:30   作者:龍小  
這篇文章主要介紹了C++初級(jí)線程管理,C++11中提供了std::thread庫(kù),本文將從線程的啟動(dòng)、線程等待、線程分離、線程傳參、線程識(shí)別等幾個(gè)方面介紹初級(jí)線程管理的知識(shí),需要的朋友可以參考一下

前言:

實(shí)際程序運(yùn)行時(shí),每個(gè)程序都有一個(gè)程序入口,線程也不例外,使用線程時(shí),需要給線程提供一個(gè)入口函數(shù),線程執(zhí)行完入口函數(shù)時(shí),線程將退出。C++11中提供了std::thread庫(kù),本文將從線程的啟動(dòng)、線程等待、線程分離、線程傳參、線程識(shí)別等幾個(gè)方面介紹初級(jí)線程管理的知識(shí)。

1 線程啟動(dòng)

C++11中,線程的啟動(dòng)終究是對(duì)std::thread的對(duì)象進(jìn)行構(gòu)造。

線程構(gòu)造的類別如下:

1.1? 線程函數(shù)無(wú)參數(shù)無(wú)返回值

此類可以說(shuō)是最簡(jiǎn)單的線程啟動(dòng),函數(shù)不需要傳參也不需要返回函數(shù)執(zhí)行結(jié)果,執(zhí)行完成后,線程自動(dòng)退出。

形如:

void FunDoingNothing();
std::thread(FunDoingNothing)


編寫(xiě)代碼時(shí),需要加上<thread>頭文件以方便編譯器能夠正確處理thread對(duì)象。

1.2? 線程函數(shù)有參數(shù)無(wú)返回值

C+=11中,thread的構(gòu)造函數(shù)中使用了可變參數(shù),這樣,可以使得構(gòu)造thread對(duì)象時(shí)可以自定義傳入?yún)?shù),

構(gòu)造函數(shù)的定義如下:

template<class F, class... Args> explicit thread(F&& f, Args&&... args);


在實(shí)際使用時(shí),線程函數(shù)有參數(shù)時(shí)可以定義形式如下:

void printMsg(int a, int b) {
  cout << "input params are:" << a <<","<<b<< endl;
}
std::thread my_thread(printMsg, 3, 4)


1.3? 調(diào)用可調(diào)用的類型構(gòu)造

使用時(shí),可以將帶有執(zhí)行函數(shù)的變量傳入thread的構(gòu)造函數(shù)中從而替換默認(rèn)的構(gòu)造函數(shù),

如下:

using namespace std;
class BackGroundTask{ 
public:
    void operator()() const{
        doSomeThing();
    }
priavte:
    doSomeThing();
};
int main(){
    BackGroundTask f;
    std::thread myThread(f);
}


上面的代碼中,在啟動(dòng)線程時(shí)同構(gòu)構(gòu)造對(duì)象f,f對(duì)象的重載函數(shù)中調(diào)用了線程運(yùn)行時(shí)要執(zhí)行的方法。但有一點(diǎn)需要注意的是,在傳入臨時(shí)的構(gòu)造對(duì)象時(shí),不經(jīng)過(guò)處理,可能會(huì)讓編譯器產(chǎn)生錯(cuò)誤的理解。

如:

std::thread myThread(BackGroundTask());


這里相當(dāng)與聲明了一個(gè)名為myTread的函數(shù), 這個(gè)函數(shù)帶有一個(gè)參數(shù)(函數(shù)指針指向沒(méi)有參數(shù)并返回BackGroundTask對(duì)象的函數(shù)), 返回一個(gè) std::thread 對(duì)象的函數(shù), 而非啟動(dòng)了一個(gè)線程。

如果要解決這個(gè)問(wèn)題,只需要如下處理即可:

std::thread myThread((BackGroundTask()));
std::thread myThread{BackGroundTask()};


當(dāng)然,也可以使用lamda表達(dá)式實(shí)現(xiàn)上述功能,如下:

std::thread myThread([]{
  doSomeThing();
  });


2 等待線程

C++11中,確保線程執(zhí)行完后,主線程在退出,需要在代碼中使用join()函數(shù),這樣就可以保證變量在線程結(jié)束時(shí)才會(huì)進(jìn)行銷毀。

2.1 join等待

在實(shí)際編程時(shí),join函數(shù)只是簡(jiǎn)單的等待或者不等待。在有些場(chǎng)景下就會(huì)不使用,如果想要進(jìn)行更加靈活的控制,需要使用C++11中提供的其他機(jī)制,這個(gè)也會(huì)在后面的推文中進(jìn)行說(shuō)明。
在編程時(shí),如果對(duì)一個(gè)線程使用了join,那么在后續(xù)的操作中如果使用joinable()執(zhí)行結(jié)果將返回false。既一旦使用了join。線程對(duì)象將不能重復(fù)使用。如下代碼中,在線程中使用join等待。

class BackGroundTask
{ 
public:
    void operator()()
{
        doSomeThing();
    } 
private:
    void doSomeThing() {cout<<"線程退出"<<endl;};
};
int main()
{
    BackGroundTask f;
    std::thread myThread(f);
    myThread.join();
    cout<<"退出"<<endl;
}


上面的代碼使用了線程等待,可以輸出正確的結(jié)果,如下:

線程退出
退出

如果將 myThread.join()語(yǔ)句注釋,再次執(zhí)行時(shí),程序?qū)?zhí)行出錯(cuò),因?yàn)樵谧泳€程還沒(méi)有結(jié)束時(shí),主線程已經(jīng)結(jié)束。

運(yùn)行結(jié)果如下:

退出
terminate called without an active exception

上面的輸出具備不確定性,代碼運(yùn)行時(shí)結(jié)果隨機(jī)。

2.2 異常場(chǎng)景的join等待

異常場(chǎng)景中,如果沒(méi)有充分考慮join的位置,就可能會(huì)產(chǎn)生因?yàn)楫惓?dǎo)致主線程先于子線程退出的情況,解決這些問(wèn)題可以通過(guò)下面兩種方法進(jìn)行處理:

2.2.1? 通過(guò)異常捕獲

通過(guò)分析代碼中的異常場(chǎng)景,對(duì)異常使用try...catch進(jìn)行捕獲,然后在需要線程等待的地方調(diào)用join()函數(shù),這種方法雖然可以輕易地捕獲問(wèn)題并對(duì)問(wèn)題進(jìn)行修復(fù),但并非是通用法則,還需要根據(jù)實(shí)際情況進(jìn)行分析。如檢查并確認(rèn)是否線程函數(shù)中是否使用了局部變量的引用等其它原因。

2.2.2 使用RAII方式進(jìn)行線程等待

RAII可以理解為資源獲取既初始化。因?yàn)槿珜?xiě)為:Resource Acquisition Is Initialization。
實(shí)際使用時(shí),通過(guò)定義一個(gè)類,然后在析構(gòu)函數(shù)中使用join函數(shù)進(jìn)行線程等待。這樣可以避免場(chǎng)景有遺漏的地方。

class thread_guard
{
private:
    std::thread& t;
public:
    explicit thread_guard(std::thread& t_):t(t_){}
    ~thread_guard()
    {
        if(t.joinable())
        {
            t.join();
        }
    } 
    thread_guard(thread_guard const&)=delete;
    thread_guard& operator=(thread_guard const&)=delete;
};


?如上,通過(guò)在將線程對(duì)象傳入到類thread_guard中,如果thread_guard類對(duì)象的局部變量被銷毀,則在析構(gòu)函數(shù)中會(huì)將線程托管到原始線程。
thread_guard中,使用delete標(biāo)識(shí),禁止生成該類的默認(rèn)拷貝構(gòu)造、以及賦值函數(shù)。
在實(shí)際編程時(shí)如果不想線程等待,可以使用detach方法,將線程和主線程進(jìn)行分離。

3 線程分離

線程分離使用detach方法,使用后將不能在對(duì)已分離的線程進(jìn)行管理,但是分離的線程可以真實(shí)的在后臺(tái)進(jìn)行運(yùn)行。當(dāng)線程退出時(shí),C++會(huì)對(duì)線程資源進(jìn)行清理和回收。
線程分離通常被用作守護(hù)線程或者后臺(tái)工作線程。

使用方法如下:

int main()
{
    BackGroundTask f;
    std::thread myThread(f);
    myThread.detach();
    cout<<"退出"<<endl;
}


4 向線程傳遞參數(shù)

向線程傳遞參數(shù)非常簡(jiǎn)單,在上面的代碼中也有提及,這里主要說(shuō)下向線程中傳遞參數(shù)的陷阱。

看下面的代碼:

void f(int i,std::string const& s);
void oops(int some_param)
{
char buffer[1024]; 
sprintf(buffer, "%i",some_param);
std::thread t(f,3,buffer);
t.detach();
}


上面的代碼中buffer是一個(gè)局部指針變量,使用后,可能會(huì)導(dǎo)致線程出現(xiàn)未定義的行為,因?yàn)閺腸har*到string的轉(zhuǎn)換時(shí)使用的是隱式轉(zhuǎn)換,但是thread在使用時(shí)會(huì)將變量拷貝到線程私有內(nèi)存,但是并不知道需要將參數(shù)進(jìn)行轉(zhuǎn)換,因此復(fù)制到私有內(nèi)存的變量就沒(méi)有轉(zhuǎn)換成期望的對(duì)象。
如果要解決這個(gè)問(wèn)題,可以在使用時(shí)直接將參數(shù)類型轉(zhuǎn)換成函數(shù)默認(rèn)的類型,在上面的例子中可以

做如下操作:

std::thread t(f,3,std::string(buffer));


但是這樣做依然存在問(wèn)題,既線程在復(fù)制變量到私有內(nèi)存時(shí),只復(fù)制了變量值,這樣在線程調(diào)用后,如果繼續(xù)使用線程函數(shù)處理后的變量時(shí)可能變量并沒(méi)有改造,依舊是線程調(diào)用之前的變量。
因此要想在函數(shù)傳參過(guò)程中使得線程拷貝時(shí)依舊保持引用,可以在線程調(diào)用時(shí)使用引用方式,

如:

std::thread t(f,3,std::ref(std::string(buffer)));


5 線程識(shí)別

每個(gè)線程都有一個(gè)線程標(biāo)識(shí),在C++11中,線程標(biāo)識(shí)通過(guò)std::thread::id進(jìn)行標(biāo)識(shí),std::thread::id可以復(fù)用并進(jìn)行比較,如果兩個(gè)線程的id相等,那么它們就是同一個(gè)線程或者沒(méi)有線程,如果不等就表示兩個(gè)是不同的線程或者其中一個(gè)線程不存在。

線程id的獲取方法有兩種,如下:

5.1 thread成員函數(shù)獲取

通過(guò)std::thread::get_id()可以獲取線程的id。

使用方法如下:

int main()
{
    BackGroundTask f;
    std::thread myThread(f);
    cout<<"線程id:"<<myThread.get_id()<<endl;
    myThread.detach();
    cout<<"退出"<<endl;
}


線程運(yùn)行結(jié)果為:

  • 線程id:139879559096064
  • 退出

5.2 std::this_thread::get_id()

線程id可以用來(lái)區(qū)分主線程和子線程,通過(guò)std::this_thread::get_id()可以先將主線程id保存,然后在和子線程進(jìn)行比較,從而區(qū)分主線程和子線程。

代碼如下:

int main()
{
    std::thread::id master_thread=std::this_thread::get_id();
    BackGroundTask f;
    std::thread myThread(f);
    if(master_thread!=myThread.get_id())
    {
        cout<<"子線程id:"<<myThread.get_id()<<endl;
    }
    myThread.detach();
    cout<<"退出"<<endl;
}


代碼中,先保存了主線程的id標(biāo)識(shí),然后獲取子線程id,比較兩個(gè)線程id。如果不相等則輸出子線程id。

代碼運(yùn)行結(jié)果如下:

子線程id:140161423791872

到此這篇關(guān)于C++初級(jí)線程管理的文章就介紹到這了,更多相關(guān)C++線程管理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Opencv實(shí)現(xiàn)聯(lián)合雙邊濾波

    Opencv實(shí)現(xiàn)聯(lián)合雙邊濾波

    這篇文章主要為大家詳細(xì)介紹了Opencv實(shí)現(xiàn)聯(lián)合雙邊濾波,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • 詳解C++設(shè)計(jì)模式編程中責(zé)任鏈模式的應(yīng)用

    詳解C++設(shè)計(jì)模式編程中責(zé)任鏈模式的應(yīng)用

    這篇文章主要介紹了C++設(shè)計(jì)模式編程中責(zé)任鏈模式的應(yīng)用,責(zé)任鏈模式使多個(gè)對(duì)象都有機(jī)會(huì)處理請(qǐng)求,從而避免請(qǐng)求的發(fā)送者和接收者之間的耦合關(guān)系,需要的朋友可以參考下
    2016-03-03
  • C++基于boost asio實(shí)現(xiàn)sync tcp server通信流程詳解

    C++基于boost asio實(shí)現(xiàn)sync tcp server通信流程詳解

    這篇文章主要介紹了C++基于boost asio實(shí)現(xiàn)sync tcp server通信的流程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • C++實(shí)現(xiàn)通訊錄系統(tǒng)項(xiàng)目實(shí)戰(zhàn)

    C++實(shí)現(xiàn)通訊錄系統(tǒng)項(xiàng)目實(shí)戰(zhàn)

    這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)通訊錄系統(tǒng)項(xiàng)目實(shí)戰(zhàn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • C++中replace()?函數(shù)的基本用法

    C++中replace()?函數(shù)的基本用法

    今天就跟大家聊聊有關(guān)C++中replace()函數(shù)的作用是什么,可能很多人都不太了解,為了讓大家更加了解,這篇文章主要給大家介紹了關(guān)于C++中replace()?函數(shù)的基本用法,需要的朋友可以參考下
    2021-11-11
  • C++ 中快排的遞歸和非遞歸實(shí)現(xiàn)

    C++ 中快排的遞歸和非遞歸實(shí)現(xiàn)

    這篇文章主要介紹了C++ 中快排的遞歸和非遞歸實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下
    2017-06-06
  • Qt實(shí)現(xiàn)畫(huà)筆功能

    Qt實(shí)現(xiàn)畫(huà)筆功能

    這篇文章主要為大家詳細(xì)介紹了Qt實(shí)現(xiàn)畫(huà)筆功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • 詳解C語(yǔ)言對(duì)字符串處理函數(shù)的實(shí)現(xiàn)方法

    詳解C語(yǔ)言對(duì)字符串處理函數(shù)的實(shí)現(xiàn)方法

    這篇文章主要為大家介紹了C語(yǔ)言對(duì)字符串處理函數(shù)的實(shí)現(xiàn)方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2021-12-12
  • C語(yǔ)言超詳細(xì)講解數(shù)據(jù)結(jié)構(gòu)中的線性表

    C語(yǔ)言超詳細(xì)講解數(shù)據(jù)結(jié)構(gòu)中的線性表

    線性表,數(shù)據(jù)結(jié)構(gòu)中最簡(jiǎn)單的一種存儲(chǔ)結(jié)構(gòu),專門(mén)用于存儲(chǔ)邏輯關(guān)系為"一對(duì)一"的數(shù)據(jù)。線性表是基于數(shù)據(jù)在實(shí)際物理空間中的存儲(chǔ)狀態(tài),又可細(xì)分為順序表(順序存儲(chǔ)結(jié)構(gòu))和鏈表
    2022-05-05
  • C語(yǔ)言結(jié)構(gòu)體數(shù)組同時(shí)賦值的另類用法

    C語(yǔ)言結(jié)構(gòu)體數(shù)組同時(shí)賦值的另類用法

    今天小編就為大家分享一篇關(guān)于C語(yǔ)言結(jié)構(gòu)體數(shù)組同時(shí)賦值的另類用法,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2018-12-12

最新評(píng)論