46 C++ 从主线程向 子线程如何传递参数 ------ join 状态下

从前面的知识我们知道,

一 启动子线程的方法有如下几种:

1.普通函数  做为 线程的启动

 thread mythread(mythreadmethod);

void mythreadmethod() {
	cout << "mythreadmethod start..." << endl;

	cout << "mythreadmethod end..." << endl;
}
int main()
{

    thread mythread(mythreadmethod);
    mythread.join();

}

2. 类对象  作为线程的启动

    Teacher141 t1;
    thread mythread1(t1);


    Teacher141 t2;
    thread mythread12(t2,20);

//创建线程的方法,使用operator()函数做为 线程的入口函数
class Teacher141 {
public:
	void operator()() {
		cout << "Teacher141 的 operator() 没有参数的方法被调用" << endl;
	}
	void operator()(int num ) {
		cout << "Teacher141 的 operator(int num) 的方法被调用: num = " << num << endl;
	}

	int m_age;
};

//operator()()做thread 启动方法入口
void main() {

	cout << " test thread start " << endl;
	//operator()()做thread 启动参数
	Teacher141 t1;
	thread mythread1(t1);

	//operator()(T t)做thread 启动参数
	Teacher141 t2;
	thread mythread12(t2,20);

	mythread1.join();
	mythread12.join();


	cout << " test thread end " << endl;

}

3. 类成员函数 作为线程的启动,注意使用的格式

    Teacher142 tea;
    thread mythread(&Teacher142::writeTeacherName,&tea);

//类的成员函数做 线程启动函数入口
class Teacher142 {
public:
	void writeTeacherName() {
		for (int i = 0; i < 1000; i++) {
			cout << " 子线程id 为 : " << this_thread::get_id() << "   i = " << i << endl;
		}
	}
};

void main() {
	Teacher142 tea;
	thread mythread(&Teacher142::writeTeacherName,&tea);

	for (int i = 0; i < 1000;i++) {
		cout << "主线程id 为 : " << this_thread::get_id() << "   i = " << i << endl;
	}
	mythread.join();
}

4. Lambda 表达式 做为线程的启动

void main() {
	std::cout << "Hello World0 start!\n";
	auto mylambdathread = []() {
		cout << "mylambdathread start..." << endl;
		cout << "mylambdathread end..." << endl;
	};
	thread mythread(mylambdathread);
	mythread.join();
}

二 从主线程传递参数给子线程,使用join方法

从前面的知识点,我们已经掌握了可以从主线程 启动 新线程了。但是没有传递参数。

这一节,我们看怎么传递参数。

1. 传递普通类型: int num ,非引用

实参和传递过来的地址值是不同的

void fun143(int num) {
	//num 的值 : 0x00000093fa6ff580 {200}
	for (int i = 0; i < 10;i++) {
		cout << "子线程 id为 = " << this_thread::get_id() << "  i = " << i << "    fun143 num = " << num << endl;
	}
	
}

void main() {
	//传递普通类型: int num ,非引用
	int a = 200;//0x00000093fa30f724 {200}
	thread mythread(fun143,a);
	for (int i = 0; i < 10;i++) {
		cout << " 主线程 id 为 " << this_thread::get_id()<< "  i = " << i <<  endl;
	}
	mythread.join();
}

2.传递C++自带类型: string str,非引用

实参和传递过来的地址值是不同的

void fun144(string str) {
	for (int i = 0; i < 10; i++) {
		//子线程 id为 = 2976  i = 0    fun144 str = nihao & str 0000004C06EFF578
		cout << "子线程 id为 = " << this_thread::get_id() << "  i = " << i << "    fun144 str = " << str <<  "  &str " << &str << endl;
	}
}
//传递C++自带类型: string str ,非引用
void main() {
	string strsource ("nihao");
	cout << "主线程 id 为 " << this_thread::get_id() << "  strsource = " << strsource <<  "  &strsource = " << &strsource << endl;
	//主线程 id 为 17956  strsource = nihao & strsource = 0000004C06B5F928
	thread mythread(fun144, strsource);
	for (int i = 0; i < 10; i++) {
		cout << " 主线程 id 为 " << this_thread::get_id() << "  i = " << i << endl;
	}
	mythread.join();
}

3.传递 自定义类型 -非引用

copy 构造函数被调用了2次,这至少说明thread 类内部肯定做了很多事情

class Teacher145 {
public:
	Teacher145(int age) :mage(age) {
		cout << "Teacher145 构造函数 mage = " << mage << "  this_thread::getid()" << this_thread::get_id()<< "  this " << this<< endl;
	}
	Teacher145(const Teacher145& obj) {
		this->mage = obj.mage;
		cout << "Teacher145 copy 构造函数" << "  this_thread::getid() = " << this_thread::get_id() << "   this = " << this <<"  &obj = " << &obj << endl;
	}
	~Teacher145() {
		cout << "Teacher145 析构函数被调用" << "  this_thread::getid() = " << this_thread::get_id() << endl;
	}
private:
	int mage;

public:
	int getAge() {
		return this->mage;
	}
};

void fun145(Teacher145 temptea) {
	cout << "子线程 this_thread::get_id() = " << this_thread::get_id() << "   &temptea = " << &temptea << "   temptea.getAge() = " << temptea.getAge() << endl;
	for (int i = 0; i < 10; ++i) {
		cout << "子线程 this_thread::get_id() = " << this_thread::get_id() << " iii = " << i << endl;
	}
}

void main() {
	Teacher145 tea(20);
	cout << "主线程 this_thread::get_id() = " << this_thread::get_id() << "   &tea = " << &tea << "   tea.getAge() = " << tea.getAge()<mage = obj.mage;
		cout << "Teacher150 copy 构造函数" << "  this_thread::getid() = " << this_thread::get_id() << "   this = " << this << "  &obj = " << &obj << endl;
	}
	~Teacher150() {
		cout << "Teacher150 析构函数被调用" << "  this_thread::getid() = " << this_thread::get_id() << endl;
	}
private:
	int mage;

public:
	int getAge() {
		return this->mage;
	}
	void setAge(int age) {
		this->mage = age;
	}
};

void func150(const Teacher150 & temptea) {
	cout << "子线程id = " << this_thread::get_id() << "  &temptea = " << &temptea << endl;

}
void main150() {
	//传递 自定义 类的引用
	Teacher150 tea(200);
	cout << "主线程id = " << this_thread::get_id() << "  &tea = " << &tea << endl;
	thread mythread(func150,tea);
	mythread.join();

	//Teacher150 构造函数 mage = 200  this_thread::getid()15860  this 000000C1B95DFB14
	//	主线程id = 15860 & tea = 000000C1B95DFB14
	//	Teacher150 copy 构造函数  this_thread::getid() = 15860   this = 0000021FCA5C2520  &obj = 000000C1B95DFB14
	//	子线程id = 8600 & temptea = 0000021FCA5C2520
	//	Teacher150 析构函数被调用  this_thread::getid() = 8600
	//	Teacher150 析构函数被调用  this_thread::getid() = 15860
}

6.2 传递 自定义类型 ref 引用

class Teacher150 {
public:
	Teacher150(int age) :mage(age) {
		cout << "Teacher150 构造函数 mage = " << mage << "  this_thread::getid()" << this_thread::get_id() << "  this " << this << endl;
	}
	Teacher150(const Teacher150& obj) {
		this->mage = obj.mage;
		cout << "Teacher150 copy 构造函数" << "  this_thread::getid() = " << this_thread::get_id() << "   this = " << this << "  &obj = " << &obj << endl;
	}
	~Teacher150() {
		cout << "Teacher150 析构函数被调用" << "  this_thread::getid() = " << this_thread::get_id() << endl;
	}
private:
	int mage;

public:
	int getAge() {
		return this->mage;
	}
	void setAge(int age) {
		this->mage = age;
	}
};


void func151( Teacher150 & temptea) {
	cout << "子线程id = " << this_thread::get_id() << "  &temptea = " << &temptea << endl;
	temptea.setAge(89);
}
void main() {
	//传递 自定义 类的引用
	Teacher150 tea(200);
	cout << "主线程id = " << this_thread::get_id() << "  &tea = " << &tea << endl;
	thread mythread(func151, ref(tea));
	mythread.join();
	cout << "tea.age = " << tea.getAge() << endl;
	//Teacher150 构造函数 mage = 200  this_thread::getid()18644  this 000000109D95F6F4
	//	主线程id = 18644 & tea = 000000109D95F6F4
	//	子线程id = 11016 & temptea = 000000109D95F6F4
	//	tea.age = 89
	//	Teacher150 析构函数被调用  this_thread::getid() = 18644
}

7. 用 类成员函数的方式实现

class Teacher161 {
public:
	Teacher161(int age) :mage(age) {
		cout << "Teacher161 构造函数 mage = " << mage << "  this_thread::getid()" << this_thread::get_id() << "  this " << this << endl;
	}
	Teacher161(const Teacher161& obj) {
		this->mage = obj.mage;
		cout << "Teacher161 copy 构造函数" << "  this_thread::getid() = " << this_thread::get_id() << "   this = " << this << "  &obj = " << &obj << endl;
	}
	~Teacher161() {
		cout << "Teacher161 析构函数被调用" << "  this_thread::getid() = " << this_thread::get_id() << endl;
	}
private:
	int mage;

public:
	int getAge() {
		return this->mage;
	}
	void setAge(int age) {
		this->mage = age;
	}
};


class Teacher160 {
public:
	void fun143(int num) {
		for (int i = 0; i < 10; i++) {
			cout << "子线程 id为 = " << this_thread::get_id() << "  i = " << i << "    fun143 num = " << num <<  " & num = " << &num  << endl;
		}
	}

	void fun144(string str) {
		for (int i = 0; i < 10; i++) {
			cout << "子线程 id为 = " << this_thread::get_id() << "  i = " << i << "    fun144 str = " << str << "  &str " << &str << endl;
		}
	}

	void fun145(Teacher161 temptea) {
		cout << "子线程 this_thread::get_id() = " << this_thread::get_id() << "   &temptea = " << &temptea << "   temptea.getAge() = " << temptea.getAge() << endl;
		for (int i = 0; i < 10; ++i) {
			cout << "子线程 this_thread::get_id() = " << this_thread::get_id() << " iii = " << i << endl;
		}
	}

	void fun146(const int &num) {//注意,这里要使用const 标识
		for (int i = 0; i < 10; i++) {
			cout << "子线程 id为 = " << this_thread::get_id() << "  i = " << i << "    fun146 num = " << num << "  &num = " << &num << endl;
		}
	}


	void fun147(int &num) {//注意,这里没有加 const 标识
		//num 的值 :=
		for (int i = 0; i < 10; i++) {
			cout << "子线程 id为 = " << this_thread::get_id() << "  i = " << i << "    fun147 num = " << num << "  &num = " << &num << endl;
		}
	}


	void fun148(const string &str) {//注意,这里要使用const 标识
		//num 的值 :=
		for (int i = 0; i < 10; i++) {
			cout << "子线程 id为 = " << this_thread::get_id() << "  i = " << i << "    fun148 string = " << str << "  &str = " << &str << endl;
		}
	}

	void fun149(string &str) {
		cout << "子线程 id为 = " << this_thread::get_id() << "    fun149 string = " << str << "  &str = " << &str << endl;
		str = "str content changed";
	}

	void func150(const Teacher161 & temptea) {
		cout << "子线程id = " << this_thread::get_id() << "  &temptea = " << &temptea << endl;

	}

	void func151(Teacher161 & temptea) {
		cout << "子线程id = " << this_thread::get_id() << "  &temptea = " << &temptea << endl;
		temptea.setAge(89);
	}

public:
	Teacher160() {
		cout << "Teacher160 构造函数" << endl;
	}
	Teacher160(int age) :m_age(age) {
		cout << "Teacher160 构造函数 int 执行" << endl;
	}
	Teacher160(const Teacher160& obj) {
		this->m_age = obj.m_age;
		cout << "Teacher160 copy 构造函数" << endl;
	}
	~Teacher160() {
		cout << "Teacher160 析构函数" << endl;
	}

private:
	int m_age;

public:
	void setTeacher160age(int age) {
		this->m_age = age;
	}

	int getTeacher160age() {
		return this->m_age;
	}
};

7.1  普通类型做参数 非引用

void main(){

    Teacher160 tea;
	int num = 10;
	cout << "主线程 " << this_thread::get_id() << " num = " << num << " &num = " <<&num << endl;
	thread mythread(&Teacher160::fun143, &tea,num);
	mythread.join();

	//  Teacher160 构造函数
	//	主线程 16888 num = 10 & num = 0000001D49DBFAD4
	//	子线程 id为 = 15876  i = 0    fun143 num = 10 & num = 0000001D4A0FF4E8
	//	子线程 id为 = 15876  i = 1    fun143 num = 10 & num = 0000001D4A0FF4E8
	//	子线程 id为 = 15876  i = 2    fun143 num = 10 & num = 0000001D4A0FF4E8
	//	子线程 id为 = 15876  i = 3    fun143 num = 10 & num = 0000001D4A0FF4E8
	//	子线程 id为 = 15876  i = 4    fun143 num = 10 & num = 0000001D4A0FF4E8
	//	子线程 id为 = 15876  i = 5    fun143 num = 10 & num = 0000001D4A0FF4E8
	//	子线程 id为 = 15876  i = 6    fun143 num = 10 & num = 0000001D4A0FF4E8
	//	子线程 id为 = 15876  i = 7    fun143 num = 10 & num = 0000001D4A0FF4E8
	//	子线程 id为 = 15876  i = 8    fun143 num = 10 & num = 0000001D4A0FF4E8
	//	子线程 id为 = 15876  i = 9    fun143 num = 10 & num = 0000001D4A0FF4E8
	//	Teacher160 析构函数

}

7.2 string 类型做参数,非引用

Teacher160 tea;
	string strsource("haoheiyou");
	cout << "主线程 " << this_thread::get_id() << " strsource = " << strsource << " &strsource = " << &strsource << endl;
	thread mythread(&Teacher160::fun144, &tea, strsource);
	mythread.join();
	//Teacher160 构造函数
	//	主线程 16348 strsource = haoheiyou & strsource = 000000351C34F8A8
	//	子线程 id为 = 13932  i = 0    fun144 str = haoheiyou & str 000000351C6FF438
	//	子线程 id为 = 13932  i = 1    fun144 str = haoheiyou & str 000000351C6FF438
	//	子线程 id为 = 13932  i = 2    fun144 str = haoheiyou & str 000000351C6FF438
	//	子线程 id为 = 13932  i = 3    fun144 str = haoheiyou & str 000000351C6FF438
	//	子线程 id为 = 13932  i = 4    fun144 str = haoheiyou & str 000000351C6FF438
	//	子线程 id为 = 13932  i = 5    fun144 str = haoheiyou & str 000000351C6FF438
	//	子线程 id为 = 13932  i = 6    fun144 str = haoheiyou & str 000000351C6FF438
	//	子线程 id为 = 13932  i = 7    fun144 str = haoheiyou & str 000000351C6FF438
	//	子线程 id为 = 13932  i = 8    fun144 str = haoheiyou & str 000000351C6FF438
	//	子线程 id为 = 13932  i = 9    fun144 str = haoheiyou & str 000000351C6FF438
	//	Teacher160 析构函数

7.3传递自定义对象做参数,非引用

	Teacher160 tea;
	Teacher161 tea161(61);
	cout << "主线程 " << this_thread::get_id() << " tea161 = " << &tea161  << endl;
	thread mythread2(&Teacher160::fun145,tea, tea161);
	mythread2.join();
	//结果是Teacher161 的构造函数调用一次,copy 构造调用函数调用2次。析构了3次

	//Teacher160 构造函数
	//	Teacher161 构造函数 mage = 61  this_thread::getid()19132  this 000000E5C099FC04
	//	主线程 19132 tea161 = 000000E5C099FC04
	//	Teacher161 copy 构造函数  this_thread::getid() = 19132   this = 0000029CFC121E90  &obj = 000000E5C099FC04
	//	Teacher160 copy 构造函数
	//	Teacher161 copy 构造函数  this_thread::getid() = 16280   this = 000000E5C0CFF0E4  &obj = 0000029CFC121E90
	//	子线程 this_thread::get_id() = 16280 & temptea = 000000E5C0CFF0E4   temptea.getAge() = 61
	//	子线程 this_thread::get_id() = 16280 iii = 0
	//	子线程 this_thread::get_id() = 16280 iii = 1
	//	子线程 this_thread::get_id() = 16280 iii = 2
	//	子线程 this_thread::get_id() = 16280 iii = 3
	//	子线程 this_thread::get_id() = 16280 iii = 4
	//	子线程 this_thread::get_id() = 16280 iii = 5
	//	子线程 this_thread::get_id() = 16280 iii = 6
	//	子线程 this_thread::get_id() = 16280 iii = 7
	//	子线程 this_thread::get_id() = 16280 iii = 8
	//	子线程 this_thread::get_id() = 16280 iii = 9
	//	Teacher161 析构函数被调用  this_thread::getid() = 16280
	//	Teacher160 析构函数
	//	Teacher161 析构函数被调用  this_thread::getid() = 16280
	//	Teacher161 析构函数被调用  this_thread::getid() = 19132
	//	Teacher160 析构函数

7.4 传递普通类型做参数,引用

	Teacher160 tea;
	int num = 60;
	cout << "主线程 " << this_thread::get_id() << " num = " << &num << endl;
	thread mythread2(&Teacher160::fun146, &tea, num);
	mythread2.join();

	//Teacher160 构造函数
	//	主线程 11392 num = 00000085E5F0F4C4
	//	子线程 id为 = 17400  i = 0    fun146 num = 60 & num = 000002453746A6D0

7.5传递普通类型做参数,使用ref函数包裹 引用

这两个地址是一样的,因此,改一个,另一个也会变。

	Teacher160 tea;
	int num = 60;
	cout << "主线程 " << this_thread::get_id() << " num = " << &num << endl;
	thread mythread2(&Teacher160::fun147, &tea, ref(num));
	mythread2.join();
	cout<<"num = "<< num << endl;

	//Teacher160 构造函数
	//	主线程 14780 num = 00000001000FFBE4
	//	子线程 id为 = 18540    fun147 num = 60 & num = 00000001000FFBE4
	//	num = 888
	//	Teacher160 析构函数

7.6传递string 类型做参数,引用

	Teacher160 tea;
	string strscource("www.baidu.com");
	cout << "主线程 " << this_thread::get_id() << " &strscource = " << &strscource <<  "   strscource = " << strscource << endl;
	thread mythread2(&Teacher160::fun148, &tea, strscource);
	mythread2.join();

	//主线程 16668 & strscource = 00000083DBD4F8D8   strscource = www.baidu.com
	//	子线程 id为 = 12156  i = 0    fun148 string = www.baidu.com  &str = 000001A5BA056200

7.7传递string 类型做参数,引用ref

	Teacher160 tea;
	string strscource("www.baidu.com");
	cout << "主线程 " << this_thread::get_id() << " &strscource = " << &strscource << "   strscource = " << strscource << endl;
	thread mythread2(&Teacher160::fun149, &tea, ref(strscource));
	mythread2.join();
	cout << "strscource = " << strscource <<  endl;

结果:
Teacher160 构造函数
主线程 15976 &strscource = 000000DF866FFBB8   strscource = www.baidu.com
子线程 id为 = 16528    fun149 string = www.baidu.com  &str = 000000DF866FFBB8
strscource = str content changed
Teacher160 析构函数

7.8传递自定义类型做参数,引用

	Teacher160 tea;
	Teacher161 tea161(81);
	cout << "主线程 " << this_thread::get_id() << " tea161 = " << &tea161  << endl;
	thread mythread2(&Teacher160::func150, &tea, tea161);
	mythread2.join();

	//即使使用了引用,Teacher161调用了构造函数,Teacher161还调用了 copy 构造函数,实际参数和形参依然不是一个地址
	//Teacher160 构造函数
	//	Teacher161 构造函数 mage = 81  this_thread::getid()16348  this 000000816273F9E4
	//	主线程 16348 tea161 = 000000816273F9E4
	//	Teacher161 copy 构造函数  this_thread::getid() = 16348   this = 000002797B7AA6D0  &obj = 000000816273F9E4
	//	子线程id = 15848 & temptea = 000002797B7AA6D0
	//	Teacher161 析构函数被调用  this_thread::getid() = 15848
	//	Teacher161 析构函数被调用  this_thread::getid() = 16348
	//	Teacher160 析构函数

7.9传递自定义类型做参数,引用 ref

使用了ref,传递的实参和形参就是一个了

Teacher160 tea;
Teacher161 tea161(91);
cout << "主线程 " << this_thread::get_id() << " tea161 = " << &tea161 << endl;
thread mythread2(&Teacher160::func151, &tea, ref(tea161));
mythread2.join();
cout << tea161.getAge()<

三,补充,如果传递的是智能指针,要注意如果是unique_ptr,则只能 join,不能deteach,传递的时候也只能move

unique_ptr,注意要用move

class Teacher162 {
        public:
	void funptr(unique_ptr ptr) {
		cout << "子线程 id为 = " << this_thread::get_id() << "    funptr *ptr = " << *ptr  <<  "  ptr = " << ptr << endl;
	}
};

void main(){

	///智能指针
	Teacher162 tea;
	unique_ptr ptr(new int(20));
	cout << "子线程的id = " << this_thread::get_id()<< " *ptr = " <<*ptr <<"   ptr = " << ptr<< endl;
	thread mythread(&Teacher162::funptr,tea,move(ptr));//注意,用的是unique_ptr,传递参数的时候,只能转移,不是copy,因此要用到move函数。。这里再复习一下一个坑点,move函数的作用是 将一个左值变成右值,本质上是调用了 移动构造函数

	mythread.join();

}

shared_ptr,注意要用move

class Teacher162 {
        public:
	void funzhinengptr(shared_ptr ptr) {
		cout << "子线程 id为 = " << this_thread::get_id() << "    funptr *ptr = " << *ptr << "  ptr = " << ptr << endl;
	}
};

void main(){

	Teacher162 tea;
	shared_ptr ptr(new int(20));
	cout << "子线程的id = " << this_thread::get_id() << " *ptr = " << *ptr << "   ptr = " << ptr << endl;
	thread mythread(&Teacher162::funzhinengptr, tea, ptr);//注意,用的是shared_ptr,传递参数的时候,可以copy,

	mythread.join();

}

四,函数参数返回值的问题。

从前面写的例子,都没有 考虑到  线程返回值情况,这个后面再分析一下,目前想不到这个返回值在实际开发中有啥用?

你可能感兴趣的:(c++)