多线程编程1. thread 基本用法
C++ 11 Thread 线程库的基本用法
1. 线程的创建
#include <thread>
std::thread th(function_name, args...);
// function_name: 线程入口点的 函数/可调用对象
// args: function_name函数对应所需传递的参数,可以没有,也可以有多个
2. 线程函数的参数传递
std::thread th(function_name, args...);
// function_name: 线程入口点的 函数/可调用对象
// args: function_name函数对应所需传递的参数,可以没有,也可以有多个
// 类成员函数作为入口函数
std::thread th(&MyClass::func, &obj, arg...);
注意:
- 如果函数的参数是引用的时候,需要注意变量的生命周期 是否在线程函数运行期间一直有效。
- 如果函数参数是引用,变量名需要用 std::ref 来包装,否则会有编译错误
void increase(int& i) {
i++;
}
int main()
{
int a = 0;
std::thread th(increase, std::ref(a));
th.join();
cout << a << endl;
return 0;
}
3. 等待线程
主线程中调用这句话时,如果th子线程还没有执行完毕,则主线程会卡在这里等待子线程执行完毕,再继续往下执行
th.join(); //等待线程执行完成
4. 分离线程
使得该线程与主线程分离,让其在后台运行,即使主线程提前结束了,子线程也会继续执行,知道结束。程序运行到这句话时不会等待,继续往下执行
th.detach(); // 分离线程,让它在后台运行
5. joinable()
判断该线程是否能够调用 join()
返回true: 说明该线程还没有被join() 或者detach
返回false: (1) 线程已经被 join() 或者 detach(); (2) 线程对象已经被移动
6. 使用多线程可能存在的一些问题
- 创建一个线程没有等待,或者分离他
- 多线程之间的数据共享,同步机制等,可能会导致数据竞争,死锁问题。
- 线程中发生的异常没有处理,可能会导致程序崩溃,尽可能使用try-catch进行异常捕捉
- 线程函数中引用了变量,如果变量的生命周期在函数运行时无效,会导致异常
4.1 传递临时变量给线程函数
4.2 传递的指针或引用指向局部变量(可以用智能指针来管理对象)
4.3 传递指针或引用指向已释放的内存问题 (本质同4.2)
4.4 类的成员函数作为入口函数,类对象被提前释放
// 类成员函数作为入口函数
std::thread th(&MyClass::func, &obj, arg...); // obj 对象被提前释放
std::shared_ptr<MyClass> obj_ptr = std::make_shared<MyClass>();
std::thread th(&MyClass::func, obj_ptr, arg...); // 利用智能指针进行管理
- 类的私有成员函数作为入口函数 (将入口函数声明成类的有元函数)