天天看点

std::ref

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;
}
           
std::ref

可以看的子线程中x值为-1,和c没关系,还有就是要注意当子线程入口为类的成员函数时,注意写法,传给thread构造函数的第一个参数格式应该是

&[类名]::[成员函数名]
           

应该只是写法是这样写,表示入口地址是该类的成员函数,记住即可

那么问题来了,这种函数(thread构造函数,bind函数)传递参数是值传递(值传递有好处的,可以防止引用已经释放的资源,比如用detach,假设引用用main线程中的局部变量temp,如果主线程结束了,子线程还在继续运行,那么所引用的tmp已经被释放了,肯定会出问题,所以值传递的话就没事,就算tmp释放了,子线程引用的是传入thread构造函数时temp的副本,因为是值传递)。

如果想要引用传递呢?可以用std::ref,表示我们想要传递的是变量本身

std::ref

还有一点很奇怪,可以用&c代替std::ref

std::ref

还有一点需要注意,在普通的函数中,ref是不起作用的

std::ref

当用ref引用时,如果是detach,那就需要注意了,比如这里的C对象c,可能主线程结束了,子线程还在运行,这时c已经释放了,如果再去访问c就会出问题,所以detach时一定要注意,一不小心容易写bug,join就容易多了