C 初級執行緒管理

2022-09-20 18:39:06 字數 3105 閱讀 9021

目錄

前言:實際程式執行時,每個程式都有乙個程式入口,執行緒也不例外,使用執行緒時,需要給執行緒提供乙個入口函式,執行緒執行完入口函式時,執行緒將退出。c++11中提供了std::thread庫,本文將從執行緒的啟動、執行緒等待、執行緒分離、執行緒傳參、執行緒識別等幾個方面介紹初級執行緒管理的知識。

c++11中,執行緒的啟動終究是對std::thread的物件進行構造。

執行緒構造的類別如下:

此類可以說是最簡單的執行緒啟動,函式不需要傳參也不需要返回函式執行結果,執行完成後,執行緒自動退出。

形如:void fundoingnothing();

std::thread(fundoingnothing)

編寫**時,需要加上標頭檔案以方便編譯器能夠正確處理thread物件。

c+=11中,thread的建構函式中使用了可變引數,這樣,可以使得構造thread物件時可以自定義傳入引數,

建構函式的定義如下:

template explicit thread(f&& f, args&&... args);

在實際使用時,執行緒函式有引數時可以定義形式如下:

void printmsg(int a, int b)www.cppcns.com

pri**te:

dosomething();

};int main()

上面的**中,在啟動執行緒時同構構造物件f,f物件的過載函式中呼叫了執行緒執行時要執行的方法。但有一點需要注意的是,在傳入臨時的構造物件時,不經過處理,可能會讓編譯器產生錯誤的理解。

如:std::thread mythread(backgroundtask());

這裡相當與宣告了乙個名為mytread的函式, 這個函式帶有乙個引數(函式指標指向沒有引數並返回backgroundtask物件的函式), 返回乙個std::thread物件的函式, 而非啟動了乙個執行緒。

如果要解決這個問題,只需要如下處理即可:

std::thread mythread((backgroundtask()));

std::thread mythread;

當然,也可以使用lamda表示式實現上述功能,如下:

std::thread mythread();

c++11中,確保執行緒執行完後,主線程在退出,需要在**中使用join()函式,這樣就可以保證變數**程結束時才會進行銷毀。

在實際程式設計時,join函式只是簡單的等待或者不等待。在有些場景下就會不使用,如果想要進行更加靈活的控制,需要使用c++11中提供的其他機制,xtrewpfe這個也會在後面的推文中進行說明。

在程式設計時,如果對乙個執行緒使用了join,那麼在後續的操作中如果使用joinable()執行結果將返回false。既一旦使用了join。執行緒物件將不能重複使用。如下**中,**程中使用join等待。

class backgroundtask

private:

void dosomething()

~thread_guard()

} thread_guard(thread_guard const&)=delete;

thread_guard& operator=(thread_guard const&)=程式設計客棧delete;

};如上,通過在將執行緒物件傳入到類thread_guard中,如果thread_guard類物件的區域性變數被銷毀,則在析構函式中會將執行緒託管到原始執行緒。

在thread_guard中,使用delete標識,禁止生成該類的預設拷貝構造、以及賦值函式。

在實際程式設計時如果不想執行緒等待,可以使用detach方法,將執行緒和主線程進行分離。

執行緒分離使用detach方法,使用後將不能在對已分離的執行緒進行管理,但是分離的執行緒可以真實的在後台進行執行。當執行緒退出時,c++會對執行緒資源進行清理和**。

執行緒分離通常被用作守護執行緒或者後台工作執行緒。

使用方法如下:

int main()

上面的**中buffer是乙個區域性指標變數,使用後,可能會導致執行緒出現未定義的行為,因為從char*到string的轉換時使用的是隱式轉換,但是thread在使用時會將變數拷貝到執行緒私有記憶體,但是並不知道需要將引數進行轉換,因此複製到私有記憶體的變數就沒有轉換成期望的物件。

如果要解決這個問題,可以在使用時直接將引數型別轉換成函式預設的型別,在上面的例子中可以

做如下操作:

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

但是這樣做依然存在問題,既執行緒在複製變數到私有記憶體時,只複製了變數值,這樣**程呼叫後,如果繼續使用執行緒函式處理後的變數時可能變數並沒有改造,依舊是執行緒呼叫之前的變數。

因此要想在函式傳參過程中使得執行緒拷貝時依舊保持引用,可以**程呼叫時使用引用方式,

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

每個執行緒都有乙個執行緒標識,在c++11中,執行緒標識通過std::thread::id進行標識,std::thread::id可以復用並進行比較,如果兩個執行緒的id相等,那麼它們就是同乙個執行緒或者沒有執行緒,如果不等就表示兩個是不同的執行緒或者其中乙個執行緒不存在。

執行緒id的獲取方法有兩種,如下:

通過std::thread::get_id()可以獲取執行緒的id。

使用方法如下:

int main()

{ backgroundtask f;

std::thread mythread(f);

cout<

執行緒執行結果為:

執行緒id可以用來區分主線程和子執行緒,通過std::this_thread::get_id()可以先將主線程id儲存,然後在和子執行緒進行比較,從而區分主線程和子執行緒。

**如下:

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標識,然後獲取子執行緒id,比較兩個執行緒id。如果不相等則輸出子執行緒id。

**執行結果如下:

子執行緒id:140161423791872

C 多執行緒初級彙總

非同步委託建立執行緒的一種簡單方式是定義乙個委託,並非同步呼叫它 委託是方法的型別安全的引用 delegate類還支援非同步地呼叫方法。在後台,delegate類會建立乙個執行任務的執行緒static void main string args int result dl.endinvoke ar ...

C 多執行緒初級一 建立執行緒

polythreaddemo.cpp 定義控制台應用程式的入口點。這裡有乙個觀點,就是當使用某個函式的時候,再 寫上頭檔案,不用一開始就來 include stdafx.h include include include using namespace std void hello int tmai...

記憶體管理初級

一.記憶體分為五大區 棧區,堆區,全域性區,常量區,區 2.棧區特點 3.堆區的特點 4.常量區的特點 5,全域性區 特點 二.記憶體管理 1.manul reference count auto reference count mrc arc referencecount 引用計數 系統根據引用計...