C++11——多線程編程15 如何在類中使用 std::thread 作為成員變量?


翻譯來自:https://thispointer.com/c11-how-to-use-stdthread-as-a-member-variable-in-class/

在本文中,我們將討論如何在類中使用 std::thread 對象作為成員變量及其好處。

由於 std::thread 對象只能移動,因此在設計一個使用 std::thread 作為成員變量的類時,我們需要注意該類的對象也應該是只能移動的。

使用 std::thread 作為成員變量創建 Move-only 類

讓我們創建一個ThreadWrapper類,它具有std::thread作為成員變量,並使其可移動,

  • 刪除其復制構造函數和賦值運算符。
  • 定義 Move 構造函數和 Move 賦值運算符。
/*
 * 一個以線程對象作為成員變量的類
 */
class ThreadWrapper
{
    // std::thread 對象
    std::thread threadHandler;
public:
//刪除復制構造函數
ThreadWrapper(const ThreadWrapper&) = delete;
//刪除賦值操作符
ThreadWrapper& operator = (const ThreadWrapper&) = delete;
// 參數化構造函數
ThreadWrapper(std::function < void()> func);
// 移動構造函數
ThreadWrapper(ThreadWrapper&& obj);
//移動賦值運算符
ThreadWrapper& operator= (ThreadWrapper && obj);
//析構函數
~ThreadWrapper();
};

它的參數化構造函數將接受回調/函數指針/函數對象作為參數,這些參數將被內部線程對象用作線程函數,即

ThreadWrapper:: ThreadWrapper ( std::function < void ()> func ) : threadHandler ( func ){}

移動構造函數和賦值運算符

在移動構造函數和賦值運算符中,我們需要移動線程對象,即

// 移動構造函數
ThreadWrapper::ThreadWrapper(ThreadWrapper&& obj) :threadHandler(std::move(obj.threadHandler))
{
    std::cout << "Move Constructor is called" << std::endl;
}
//移動賦值運算符
ThreadWrapper& ThreadWrapper::operator=(ThreadWrapper&& obj)
{
    std::cout << "Move Assignment is called" << std::endl;
    if (threadHandler.joinable())
        threadHandler.join();
    threadHandler = std::move(obj.threadHandler);
    return *this;
}

在移動賦值運算符中,我們首先需要加入當前線程對象(如果它是可連接的),然后再用新的線程對象替換它。

在ThreadWrapper的析構函數中我們需要加入線程對象。這是必要的,因為如果線程對象在沒有加入的情況下被破壞,那么它將終止應用程序即

// Destructor : Join the thread object
ThreadWrapper::~ThreadWrapper()
{
    if (threadHandler.joinable())
        threadHandler.join();
}

現在讓我們創建一個 ThreadWrapper 對象,現在當這個對象被析構時,內部線程將加入析構函數即

// 創建一個 std::function 對象
std::function<void()> func = []() {
    // 休眠 1 秒
    std::this_thread::sleep_for(std::chrono::seconds(1));
    // 打印線程ID
    std::cout << "From Thread ID : " << std::this_thread::get_id() << "\n";
};
{
    // 創建一個 ThreadWrapper 對象
    // 它會在內部啟動線程
    ThreadWrapper wrapper(func);
    //當包裝器超出范圍時,將調用其析構函數
    // 這將在內部加入成員線程對象
}

此外,我們可以創建一個 ThreadWraper 向量,即

// 創建一個 ThreadWrapper 對象的向量
std::vector < ThreadWrapper > vecOfThreads;

 

// 在線程中添加 ThreadWrapper 對象
ThreadWrapper thwp1 ( func ) ;
ThreadWrapper thwp2 ( func ) ;
vecOfThreads。push_back ( std:: move ( thwp1 )) ;
vecOfThreads。push_back ( std:: move ( thwp2 )) ;

 

我們甚至不需要單獨加入線程,當vector被破壞時它會自動加入。我們也可以改變vector的內容,即

ThreadWrapper thwp3 ( func ) ;
// 改變vector的內容
vecOfThreads [ 1 ] = std:: move ( thwp3 );

 

#include <thread>
#include <mutex>
#include <vector>
#include <iostream>
#include <assert.h>
#include <chrono>
/*
 * A class that has thread object as member variable
 */
class ThreadWrapper
{
    // std::thread object
    std::thread  threadHandler;
public:
    //Delete the copy constructor
    ThreadWrapper(const ThreadWrapper&) = delete;
    //Delete the Assignment opeartor
    ThreadWrapper& operator=(const ThreadWrapper&) = delete;
    // Parameterized Constructor
    ThreadWrapper(std::function<void()> func);
    // Move Constructor
    ThreadWrapper(ThreadWrapper && obj);
    //Move Assignment Operator
    ThreadWrapper & operator=(ThreadWrapper && obj);
    //Destructor
    ~ThreadWrapper();
};
// Parameterized Constructor
ThreadWrapper::ThreadWrapper(std::function<void()> func) : threadHandler(func)
{}
// Move Constructor
ThreadWrapper::ThreadWrapper(ThreadWrapper && obj) : threadHandler(std::move(obj.threadHandler))
{
    std::cout << "Move Constructor is called" << std::endl;
}
//Move Assignment Operator
ThreadWrapper & ThreadWrapper::operator=(ThreadWrapper && obj)
{
    std::cout << "Move Assignment is called" << std::endl;
    if (threadHandler.joinable())
        threadHandler.join();
    threadHandler = std::move(obj.threadHandler);
    return *this;
}
// Destructor
ThreadWrapper::~ThreadWrapper()
{
    if (threadHandler.joinable())
        threadHandler.join();
}
int main()
{
    // Creating a std::function object
    std::function<void()> func = []() {
        // Sleep for 1 second
        std::this_thread::sleep_for (std::chrono::seconds(1));
        // Print thread ID
        std::cout << "From Thread ID : " << std::this_thread::get_id() << "\n";
    };
    {
        // Create a ThreadWrapper object
        // It will internally start the thread
        ThreadWrapper wrapper(func);
        //When wrapper will go out of scope, its destructor will be called
        // Which will internally join the member thread object
    }
    // Create a vector of ThreadWrapper objects
    std::vector<ThreadWrapper> vecOfThreads;
    // Add ThreadWrapper objects in thread
    ThreadWrapper thwp1(func);
    ThreadWrapper thwp2(func);
    vecOfThreads.push_back(std::move(thwp1));
    vecOfThreads.push_back(std::move(thwp2));
    ThreadWrapper thwp3(func);
    // Change the content of vector
    vecOfThreads[1] = std::move(thwp3);
    //When vector will go out of scope, its destructor will be called, which will
    // internally call the destructor all ThreadWrapper objects , which in turn
    // joins the member thread object.
    return 0;
}

 


From Thread ID : 16312
Move Constructor is called
Move Constructor is called
Move Constructor is called
Move Assignment is called
From Thread ID : 21792
From Thread ID : 19224
From Thread ID : 30452

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM