创建临时对象为线程参数

用detach时,子线程引用主函数中的参数会引发很多问题,例如:变量还没有复制到子线程中就已经被收回。

  • 若传递int这种简单类型参数,建议是值传递,必要用引用和指针,避免界外生枝。
  • 如果传递类对象,避免隐式类型转换。全部在创建线程这一行构建出临时对象来,然后在函数参数里,用引用来接,否者会多构造一次对象。

建议不适用detach(),只使用join():这样就不会出现局部变量失效导致的线程对非法内存的引用。

#include<iostream>
#include<thread>

using namespace std;


class A
{
public:
	int a;
	A(int ai) :a(ai)
	{
		cout << "我是构造函数" << "线程id:" << std::this_thread::get_id() << endl;
	}
	A(const A &a)
	{
		cout << "我是拷贝构造函数" << "线程id:" << std::this_thread::get_id() << endl;
	}
	~A()
	{
		cout << "我是析构函数" << "线程id:" << std::this_thread::get_id() << endl;
	}
};
void myfunc(int i,A &a)//用引用接
{
	
	cout << "myfunc函数执行" << "线程id:" << std::this_thread::get_id() << endl;
}

int main()
{
	int var1 = 9;
	int var2 = 10;
	cout << "主线程id:" << std::this_thread::get_id() << endl;
	thread t1(myfunc, var1, A(var2));//创建一个临时对象

	t1.detach();

	system("pause");
	return 0;
}

结果:

可以看出子线程会进行类创建,这样就不会有问题了,这与这里为什么在主线程中构建了好几次类,具体原因我也不清楚,如果有网友知道原因,可以给我留言。

  1. 线程id的概念,每个线程都对应一个数字类型的id,并且每个线程的id是唯一的,获得线程id:std::this_thread::get_id().
    
    /**************用隐士类型转化的时候,类对象是在子线程中创建的**********************/
    /**************可以分别在类的构造函数和子线程入口函数中打印当前线程id的方式加以验证**********************/
    
    #include<iostream>
    #include<thread>
    
    using namespace std;
    
    
    class A
    {
    public:
    	int a;
    	A(int ai) :a(ai)
    	{
    		cout << "我是构造函数" << "线程id:" << std::this_thread::get_id() << endl;
    	}
    	A(const A &a)
    	{
    		cout << "我是拷贝构造函数"<< "线程id:" << std::this_thread::get_id()  << endl;
    	}
    	~A()
    	{
    		cout << "我是析构函数"<< "线程id:" << std::this_thread::get_id()  << endl;
    	}
    };
    void myfunc(int i,A a)//直接用对象接受
    {
    	
    	cout << "myfunc函数执行" << "线程id:" << std::this_thread::get_id() << endl;
    }
    
    int main()
    {
    	int var1 = 9;
    	int var2 = 10;
    	cout << "主线程id:" << std::this_thread::get_id() << endl;
    	thread t1(myfunc, var1, var2);//用隐式类型转化的方式
    	t1.detach();
    
    	system("pause");
    	return 0;
    }
    

     

  2. 结果为:在这里插入图片描述

    从以上的例子可以看出,在一般情况下,为了安全起见,操作系统会将主线程中的变量拷贝一份到子线程中,也就是如果在子线程中对变量进行修改,不会影响到主线程中的参数变化。那么会有一个问题,如果我需要子线程中的变化传到主线程中,就需要用到std::ref()函数,表示直接主线程中的地址传进去。这样就不会调用拷贝构造函数了。

    
    #include<iostream>
    #include<thread>
    
    using namespace std;
    
    
    class A
    {
    public:
    	int a;
    	A(int ai) :a(ai)
    	{
    		cout << "我是构造函数" << "线程id:" << std::this_thread::get_id() << endl;
    	}
    	A(const A &a)
    	{
    		cout << "我是拷贝构造函数" << "线程id:" << std::this_thread::get_id() << endl;
    	}
    	~A()
    	{
    		cout << "我是析构函数" << "线程id:" << std::this_thread::get_id() << endl;
    	}
    };
    void myfunc(A &a)//此处要用引用接受。否者不能进行修改
    {
    	
    	cout << "myfunc函数执行" << "线程id:" << std::this_thread::get_id() << endl;
    	a.a=20;
    }
    
    int main()
    {
    	cout << "主线程id:" << std::this_thread::get_id() << endl;
    	int var1 = 9;
    	int var2 = 10;
    	A a(var1);
    	cout << "线程执行前:" << a.a << endl;
    	thread t1(myfunc, std::ref(a));//用隐式类型转化的方式
    	
    	//t1.detach();
    	t1.join();
    	cout << "线程执行后:" << a.a << endl;
    
    	system("pause");
    	return 0;
    }
    

     

     

注意:在子线程函数中一定要用引用接受,如果没有用引用又相当于传进去的是副本。

用智能指针创建线程

 

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐