thread构造函数中,第一个为可调用对象,后面的是可变数量的参数(类似于标准库bind函数),这种函数的参数都是值传递的,可以验证
# include<iostream>
# include<thread>
using namespace std;
class C
{
public:
C(const int&c):x(c)
{
cout << "构造函数"<<"线程id:"<<this_thread::get_id() << endl;
}
C(const C&c)
{
x = -1;
cout << "拷贝构造函数" << "线程id:" << this_thread::get_id() << endl;
}
~C()
{
cout << "析构函数" << "线程id:" << this_thread::get_id() << endl;
}
void thread_address(int i)
{
cout << "x:"<<x << endl;
}
int x;
};
int main()
{
C c(3);
cout << "main线程id:" << this_thread::get_id() << endl;
//thread t(&C::thread_address, std::ref(c), 7);
thread t(&C::thread_address, c, 7);//函数式编程可调用对象中,参数传递都是值拷贝,传入c,会
//产生临时变量,不信?c的x为7,在入口函数里并没有改变x的值,拷贝构造函数里也没有改变x,如果传给子线程
//的是c,那么子线程中x应该为3,如果传入的是临时变量,临时变量的x应该是拷贝构造函数中设置的,
t.join();
return 0;
}
可以看的子线程中x值为-1,和c没关系,还有就是要注意当子线程入口为类的成员函数时,注意写法,传给thread构造函数的第一个参数格式应该是
&[类名]::[成员函数名]
应该只是写法是这样写,表示入口地址是该类的成员函数,记住即可
那么问题来了,这种函数(thread构造函数,bind函数)传递参数是值传递(值传递有好处的,可以防止引用已经释放的资源,比如用detach,假设引用用main线程中的局部变量temp,如果主线程结束了,子线程还在继续运行,那么所引用的tmp已经被释放了,肯定会出问题,所以值传递的话就没事,就算tmp释放了,子线程引用的是传入thread构造函数时temp的副本,因为是值传递)。
如果想要引用传递呢?可以用std::ref,表示我们想要传递的是变量本身
还有一点很奇怪,可以用&c代替std::ref
还有一点需要注意,在普通的函数中,ref是不起作用的
当用ref引用时,如果是detach,那就需要注意了,比如这里的C对象c,可能主线程结束了,子线程还在运行,这时c已经释放了,如果再去访问c就会出问题,所以detach时一定要注意,一不小心容易写bug,join就容易多了