首頁 > 軟體

C++ std::thread 使用方法

2023-03-19 06:03:40

C++是一種高階程式語言,被廣泛用於開發高效能、大規模、複雜的軟體系統。其中一個強大的特性就是多執行緒程式設計,而std::thread是C++標準庫提供的多執行緒支援的重要組成部分。

std::thread是一個輕量級執行緒類,它允許程式設計師建立、啟動、停止、等待執行緒。與其他多執行緒庫不同,std::thread在執行時不需要顯式地建立和銷燬執行緒,而是通過構造和解構執行緒物件來完成這些操作。

一、std::thread的構造和解構

std::thread的建構函式需要傳入一個可呼叫物件,這個可呼叫物件可以是一個函數指標、一個函數物件、一個lambda表示式或一個類成員函數指標。建立執行緒的方式非常簡單,例如:

void my_func()
{
    // do something
}

std::thread my_thread(my_func); // 使用函數指標建立執行緒

執行緒物件建立後,它的執行路徑就已經開始了。我們可以通過std::thread物件的join()方法等待執行緒結束並阻塞主執行緒:

std::thread my_thread(my_func);
my_thread.join(); // 阻塞主執行緒等待子執行緒結束

當執行緒物件被銷燬時,它會自動呼叫解構函式,如果執行緒沒有被join()或detach(),則程式會終止並丟擲std::terminate異常。

std::thread my_thread(my_func);
// 不呼叫join()或detach()
// 當my_thread物件離開作用域時會丟擲std::terminate異常

二、std::thread的成員函數

std::thread類還有一些非常有用的成員函數,可以幫助我們管理執行緒的生命週期、獲取執行緒資訊和控制執行緒行為。

1.join()和detach()
join()方法可以阻塞主執行緒等待子執行緒結束,而detach()方法則將執行緒物件與底層執行緒分離,使得執行緒物件的生命週期不再受限於執行緒的生命週期。

std::thread my_thread(my_func);
my_thread.detach(); // 分離執行緒,執行緒物件的生命週期不再受限於執行緒的生命週期

2.get_id()

get_id()方法返回執行緒物件所代表的執行緒的唯一識別符號,這個識別符號可以用來比較不同的執行緒物件是否代表同一個執行緒。

std::thread my_thread1(my_func);
std::thread my_thread2(my_func);
if (my_thread1.get_id() == my_thread2.get_id())
{
    // 不會執行到這裡
}

3.hardware_concurrency()
hardware_concurrency()方法返回計算機硬體支援的並行執行緒數,這個值通常等於處理器的核心數。

std::cout << "可用執行緒數:" << std::thread::hardware_concurrency() << std::endl;

三、執行緒間的通訊

執行緒間的通訊是多執行緒程式設計中的一個重要問題,std::thread類提供了一些機制來幫助我們實現執行緒間的通訊和同步。

1.std::atomic
std::atomic是一個原子型別,它可以保證對該型別的操作是原子的,即不會被其他執行緒中斷。std::atomic可以用於實現執行緒間的共用變數。

std::atomic<int> counter{0};
void my_func()
{
    counter++;
}

int main()
{
    std::thread t1(my_func);
    std::thread t2(my_func);
    t1.join();
    t2.join();
    std::cout << counter << std::endl; // 輸出2
    return 0;
}

2.std::mutex和std::lock_guard
std::mutex是一個互斥量,它可以用於實現執行緒間的互斥存取。std::lock_guard是一個RAII風格的互斥量保護器,它可以在建構函式中獲取互斥量的鎖,在解構函式中釋放互斥量的鎖。

std::atomic<int> counter{0};
void my_func()
{
    counter++;
}

int main()
{
    std::thread t1(my_func);
    std::thread t2(my_func);
    t1.join();
    t2.join();
    std::cout << counter << std::endl; // 輸出2
    return 0;
}

3.std::condition_variable
std::condition_variable是一個條件變數,它可以用於實現執行緒間的同步。std::condition_variable通常與std::unique_lock一起使用,可以實現執行緒的等待和喚醒操作。

std::mutex my_mutex;
std::condition_variable my_cv;
bool ready = false;
void my_func()
{
    std::unique_lock<std::mutex> lock(my_mutex); // 獲取互斥量的鎖
    ready = true;
    my_cv.notify_one(); // 喚醒等待中的執行緒
}

int main()
{
    std::thread t1(my_func);
    std::unique_lock<std::mutex> lock(my_mutex);
    my_cv.wait(lock, []{return ready;}); // 等待執行緒的喚醒
    t1.join();
    return 0;
}

四、執行緒的例外處理

多執行緒程式中的例外處理是一個複雜的問題,std::thread類提供了一些機制來幫助我們處理執行緒中的異常。

1.try-catch塊
線上程函數中使用try-catch塊可以捕獲執行緒中的異常,防止異常影響其他執行緒和整個程式。

void my_func()
{
    try
    {
        // do something
    }
    catch (const std::exception& e)
    {
        // 處理異常
    }
}

int main()
{
    std::thread t1(my_func);
    std::thread t2(my_func);
    t1.join();
    t2.join();
    return 0;
}

2.std::terminate
std::terminate是一個函數,它可以用於終止程式的執行。當執行緒中發生未被捕獲的異常時,程式會自動呼叫std::terminate函數來終止程式的執行。

void my_func()
{
    throw std::runtime_error("something went wrong");
}

int main()
{
    std::thread t1(my_func);
    std::thread t2(my_func);
    t1.join();
    t2.join();
    return 0;
}

在上面的程式碼中,my_func函數會丟擲一個std::runtime_error異常,如果這個異常沒有被try-catch塊捕獲,程式就會呼叫std::terminate函數來終止程式的執行。

3.std::exception_ptr
std::exception_ptr是一個類,它可以用於儲存執行緒中發生的異常。我們可以在主執行緒中呼叫std::exception_ptr::rethrow_exception函數來重新丟擲執行緒中的異常。

std::exception_ptr my_exception;
void my_func()
{
    try
    {
        // do something
    }
    catch (...)
    {
        my_exception = std::current_exception(); // 儲存異常
    }
}

int main()
{
    std::thread t1(my_func);
    std::thread t2(my_func);
    t1.join();
    t2.join();
    if (my_exception)
    {
        try
        {
            std::rethrow_exception(my_exception); // 重新丟擲異常
        }
        catch (const std::exception& e)
        {
            // 處理異常
        }
    }
    return 0;
}

在上面的程式碼中,my_func函數會捕獲任何型別的異常,並將異常儲存到my_exception變數中。在主執行緒中,如果my_exception變數中儲存了異常,我們就呼叫std::rethrow_exception函數重新丟擲異常,並在catch塊中處理異常。

五、總結

C++11中的std::thread類是一個強大的多執行緒程式設計工具,它可以幫助我們輕鬆地建立和管理執行緒。通過std::thread類,我們可以實現執行緒的建立、啟動、停止、等待和同步等操作,並可以使用各種機制來處理執行緒中的異常和實現執行緒間的通訊。

在使用std::thread類時,我們需要注意以下幾點:

  • 執行緒函數必須是可呼叫物件,如函數、函數指標、函數物件等。
  • 執行緒函數的引數必須是可拷貝的,否則需要使用std::ref包裝。
  • 執行緒物件必須在主執行緒中加入join或detach,否則會導致程式異常。
  • 執行緒中發生的異常需要進行處理,否則會導致程式崩潰。

執行緒間的通訊需要使用std::atomic、std::mutex、std::lock_guard和std::condition_variable等機制。

std::thread類是一個非常強大的多執行緒程式設計工具,它可以幫助我們實現各種複雜的多執行緒應用。熟練掌握std::thread類的使用方法和機制可以提高我們的多執行緒程式設計技能,也可以幫助我們更好地處理執行緒中的異常和實現執行緒間的通訊。

最後,還有一些需要注意的點:

1.執行緒安全

多執行緒程式設計中一個非常重要的概念就是執行緒安全。如果多個執行緒同時存取同一個共用資源,可能會出現資料競爭(data race),導致程式出現不可預期的行為。

為了避免資料競爭,我們需要使用執行緒同步機制來保護共用資源。常用的執行緒同步機制包括std::mutex、std::lock_guard、std::unique_lock和std::condition_variable等。這些同步機制可以幫助我們實現互斥鎖、條件變數等功能,以確保多個執行緒之間的正確協同工作。

2.執行緒池
執行緒池(thread pool)是一個管理一組執行緒的物件。執行緒池可以幫助我們管理執行緒的數量、複用執行緒資源、避免執行緒的建立和銷燬等操作,從而提高多執行緒應用程式的效率。

C++標準庫中並沒有提供執行緒池的實現,但是我們可以使用第三方庫或自己編寫程式碼來實現執行緒池。常用的第三方執行緒池庫包括Boost.Thread和Intel TBB等。

3.並行程式設計模型
並行程式設計模型是一種抽象的概念,它描述了多個任務之間的互動和協同工作。常用的並行程式設計模型包括訊息傳遞模型、共用記憶體模型和資料流模型等。

訊息傳遞模型(message passing)是指多個任務之間通過訊息傳遞來進行通訊和同步。共用記憶體模型(shared memory)是指多個任務之間通過共用記憶體來進行通訊和同步。資料流模型(data flow)是指多個任務之間通過資料流來進行通訊和同步。

C++中的std::thread類可以用於實現多個任務之間的並行程式設計模型。在使用std::thread類時,我們需要考慮執行緒間的同步和通訊問題,以確保多個執行緒之間的正確協同工作。

4.多執行緒效能優化
在進行多執行緒程式設計時,我們需要考慮多執行緒效能優化問題。常用的多執行緒效能優化方法包括:

(1)避免執行緒的建立和銷燬。執行緒的建立和銷燬是比較耗時的操作,如果頻繁地建立和銷燬執行緒,會影響多執行緒應用程式的效能。我們可以使用執行緒池來複用執行緒資源,從而避免執行緒的建立和銷燬。

(2)減少鎖的使用。鎖是一種執行緒同步機制,但是鎖的使用會影響多執行緒應用程式的效能。如果多個執行緒之間存取同一個共用資源,可以使用無鎖資料結構來避免鎖的使用,從而提高多執行緒應用程式的效能。

(3)避免執行緒間的頻繁通訊。執行緒間的通訊是需要開銷的,如果頻繁地進行執行緒間的通訊,會影響多執行緒應用程式的效能。我們可以考慮將通訊的資料快取起來,減少執行緒間的頻繁通訊。

(4)使用本地變數。在多執行緒程式設計中,本地變數的存取不需要鎖,可以提高多執行緒應用程式的效能。如果需要存取共用資源,可以將共用資源拷貝到本地變數中,從而避免鎖的使用。

(5)使用任務並行模型。任務並行模型是一種並行程式設計模型,它可以將一個大任務劃分為多個小任務,然後將小任務分配給多個執行緒來並行執行。這樣可以提高多執行緒應用程式的效能。

總結:

C++中的std::thread類提供了一種方便的多執行緒程式設計方式。在使用std::thread類時,我們需要注意執行緒間的同步和通訊問題,以確保多個執行緒之間的正確協同工作。同時,我們還需要考慮多執行緒效能優化問題,以提高多執行緒應用程式的效能。

除了std::thread類,C++標準庫還提供了一些其他的多執行緒程式設計工具,例如std::async、std::future、std::promise等,它們都可以用於實現多執行緒程式設計。在進行多執行緒程式設計時,我們需要根據具體的應用場景選擇合適的多執行緒程式設計工具。

最後,多執行緒程式設計是一項非常複雜的任務,需要有一定的經驗和技能才能掌握。建議初學者從簡單的例子開始,逐步深入瞭解多執行緒程式設計的相關概念和技術。

到此這篇關於C++ std::thread 如何使用?的文章就介紹到這了,更多相關C++ std::thread使用內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com