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