C++11线程传递参数的陷阱

C++11线程传递参数陷阱

一、传递引用以及指针

#include <iostream>
#include <thread>

void print(const int& var, const char* str)
{
	std::cout << "print &var = " << &var << "\tstr = " << (void*)str << std::endl;
}

int main()
{
	int var = 3;
	const char str[] = "hello world!";
	std::cout << "main &var = " << &var << "\tstr = " << (void*)str << std::endl;
	std::thread mythread(print, var, str);
	mythread.join();
	return 0;
}

在这里插入图片描述
可以看到子线程和主线程中var的地址不同,str的地址相同,那var是用引用传递的为什么会出现地址不一样,是因为thread内部对var进行了复制而不是引用传递,需要引用传递需要使用std::ref来解决
在这里插入图片描述
在这里插入图片描述
这样主线程和子线程的var地址就相同了,但仍存在问题,如果将join换为detach,主线程和子线程分离,则会存在主线程执行完毕,局部变量空间呗操作系统回收,子线程在操作时,就会发生异常,所有要谨慎使用detach。

二、参数传递中存在隐式转换

#include <iostream>
#include <thread>
class A
{
public:
	int temp;
	A(int var) :temp(var) 
	{
		std::cout << "构造函数执行" << std::endl;
		std::cout << "执行的线程ID为" << std::this_thread::get_id() << std::endl << std::endl;
	}
	A(const A& Ta) :temp(Ta.temp)
	{
		std::cout << "拷贝构造函数执行" << std::endl;
		std::cout << "执行的线程ID为" << std::this_thread::get_id() << std::endl << std::endl;
	}
	~A()
	{
		std::cout << "析构函数执行" << std::endl;
		std::cout << "执行的线程ID为" << std::this_thread::get_id() << std::endl << std::endl;
	}
};
void print(const int& var,const  A& a)
{
	std::cout << "子线程开始执行" << std::endl;
	std::cout << "子线程ID为" << std::this_thread::get_id() << std::endl << std::endl;
}

int main()
{
	int var = 3;
	int a = 1;

	std::cout << "主执行的线程ID为" << std::this_thread::get_id() << std::endl << std::endl;
	std::thread mythread(print, std::ref(var), a);
	mythread.join();

	return 0;
}

在这里插入图片描述
可以观察到在参数传递中在子线程中对变量a进行了隐式转换为类A的对象,但是执行的构造的线程为子线程,如果不使用join使用detach可能存在子线程执行完毕,变量a已经被释放再在子线程进行构造会发生异常。如果需要解决这个问题,可以在主线程中构造一个临时对象。
在这里插入图片描述
在这里插入图片描述
可以看见创建临时对象后构造是在主线程之中完成,可以避免使用detach主线程结束,子线程还未结束发生异常的问题,但是可以发现又多了一次的拷贝构造函数,此时使用std::ref可以减少这次的拷贝构造。
在这里插入图片描述在这里插入图片描述

三、参数传递智能指针

#include <iostream>
#include <thread>

void print(const std::unique_ptr<int> p)
{
	std::cout << "子线程p = " << p << std::endl;
	std::cout << "线程开始执行" << std::endl;
}
int main()
{
	std::unique_ptr<int> p(new int(5));
	std::cout << "主线程p = " << p << std::endl;
	std::thread mythread(print,std::move(p));
	std::cout << "主线程p = " << p << std::endl;
	mythread.join();
	return 0;
}

在这里插入图片描述
unique_ptr在作为参数时需要使用std::move进行传递,在传递参数后,主线程的p就是一个空指针了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值