C++多线程编程:深入剖析std::thread的使用方法
一、线程std::thread简介
std::thread是 C++11 中引入的一个库,用于实现多线程编程。它允许程序创建和管理线程,从而实现并发执行。std::thread在#include<thread>头文件中声明,因此使用std::thread时需要包含#include<thread>头文件。
二、语法
2.1、构造函数
(1)默认构造函数:创建一个空的 thread 执行对象。
代码语言:C++
自动换行
AI代码解释
thread() _NOEXCEPT { // construct with no thread _Thr_set_null(_Thr); }
(2)初始化构造函数:创建std::thread执行对象,该thread对象可被joinable,新产生的线程会调用threadFun函数,该函 数的参数由args给出。
代码语言:C++
自动换行
AI代码解释
template<class Fn,class ... Args> explicit thread(Fn&& fn,Args&& ... args);
&&表示既可以传入左值也可以传入右值。
(3)拷贝构造函数。
代码语言:C++
自动换行
AI代码解释
// 如果拷贝构造函数(被禁用),意味着 thread 不可被拷贝构造。 thread(const thread&) = delete;
(4)move构造函数 。
代码语言:C++
自动换行
AI代码解释
thread(thread&& x)noexcept
move构造函数,调用成功之后x不代表任何thread执行对象。注意:可被joinable的thread对象必须在他们销毁之前被主线程join或者将其设置为detached。
示例:
展开
代码语言:C++
自动换行
AI代码解释
#include <iostream> #include <thread> using namespace std; void thread_func(int &a) { cout << "thread_func: a = " << (a += 10) << endl; } int main() { int x = 10; thread t1(thread_func, ref(x)); thread t2(move(t1)); // t1 线程失去所有权 thread t3; t3 = move(t2); // t2 线程失去所有权 // t1.join(); //执行会报错:已放弃 (核心已转储) t3.join(); cout << "main end: x = " << x << endl; return 0; }
执行结果:
代码语言:Bash
自动换行
AI代码解释
thread_func: a = 20 main end: x = 20
2.2、主要成员函数
(1)get_id():获取线程ID,返回类型std::thread::id对象。(2)joinable():判断线程是否可以加入等待。(3)join():等该线程执行完成后才返回。(4)detach():detach调用之后,目标线程就成为了守护线程,驻留后台运行,与之关联的std::thread对象失去对目标线程的关联,无法再通过std::thread对象取得该线程的控制权。当线程主函数执行完之后,线程就结束了,运行时库负责清理与该线程相关的资源。
调用 detach 函数之后:
*this不再代表任何的线程执行实例。joinable() == falseget_id() == std::thread::id()
三、简单线程的创建
使用std::thread创建线程,提供线程函数或者函数对象,并可以同时指定线程函数的参数。
传入0个值
传入2个值
传入引用
传入类函数
detachmove
(1)传入0个值:
展开
代码语言:C++
自动换行
AI代码解释
#include <iostream> #include <thread> using namespace std; void thread_func1() { cout << "thread_func1()" << endl; } int main() { thread t1(&thread_func1); // 只传递函数 t1.join(); // 阻塞等待线程函数执行结束 return 0; }
(2)传入2个值:
展开
代码语言:C++
自动换行
AI代码解释
#include <iostream> #include <thread> using namespace std; void thread_func2(int a, int b) { cout << "thread_func2(): a + b =" << a + b << endl; } int main() { int a = 10; int b = 16; thread t2(thread_func2, a, b); t2.join(); return 0; }
(3)传入引用:
展开
代码语言:C++
自动换行
AI代码解释
#include <iostream> #include <thread> using namespace std; void thread_func3(int &c) { cout << "thread_func3(): &c = " << &c cout << " --> c + 10 =" << (c += 10) << endl; } int main() { int c = 10; thread t3(thread_func3, ref(c)); t3.join(); cout << "main --> 3 : &c = " << &c << ", c = " << c << endl; return 0; }
(4)传入类函数:
展开
代码语言:C++
自动换行
AI代码解释
#include <iostream> #include <thread> using namespace std; class A { public: void func4(int a) { cout << "thread:" << name_ << ", fun4 a = " << a << endl; } void setName(string name) { name_ = name; } void displayName() { cout << "this:" << this << ", name:" << name_ << endl; } void play() { std::cout << "play call!" << std::endl; } private: string name_; }; int main() { cout << "test--------------------------" << endl; A *a_ptr = new A(); a_ptr->setName("hello,C++11"); thread t4(A::func4, a_ptr, 10); t4.join(); delete a_ptr; A *a_ptr2 = new A(); a_ptr2->setName("hello,C++14"); thread t42(&A::func4, a_ptr2, 10);// 传入类的函数地址、类地址、参数 t42.join(); delete a_ptr; return 0; }
最好使用取地址符&的方式传入类函数,避免兼容问题。
(5)detach() :将子线程从主线程中分离出来,主线程不再具有管理此子线程的能力。
展开
代码语言:C++
自动换行
AI代码解释
#include <iostream> #include <thread> using namespace std; void thread_func5() { cout << "func5 into sleep " << endl; this_thread::sleep_for(chrono::seconds(2)); cout << "func5 leave " << endl; } int main() { thread t5(&thread_func5); t5.detach(); // t5.join() // 抛出异常 cout << "t5 id : " << t5.get_id() << endl; // 抛出异常 cout << "t5 joinable: " << t5.joinable() << endl; return 0; }
执行结果:
代码语言:Bash
自动换行
AI代码解释
t5 id : thread::id of a non-executing thread t5 joinable: 0
(6)std::move() :线程所有权转移。
展开
代码语言:C++
自动换行
AI代码解释
#include <iostream> #include <thread> using namespace std; int main() { thread t6(func6); thread t7(move(t6)); //t6.join(); // 抛出异常 cout << "t6 id : " << t6.get_id() << endl; cout << "t6 joinable: " << t6.joinable() << endl; cout << "t7 joinable: " << t7.joinable() << endl; t7.join(); return 0; }
执行结果:
代码语言:Bash
自动换行
AI代码解释
t6 id : thread::id of a non-executing thread t6 joinable: 0 t7 joinable: 1 this is func6 !
四、线程封装
封装线程,子类能继承,然后子类能实现具体的业务逻辑。创建线程通过new来实现,参数列表和使用构造函数创建是一样的。
