C++并发(二)数据传递

186 阅读1分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

本章主要介绍C++线程传递参数的问题,传递参数有传递简单数据类型和传递指针等数据类型,下面来一起看下

1、传递简单数值

先看一个简单的例子

void test(int i,int j) {
	cout << "子线程运行 start" << endl;
	i = i + 10;
	j = j + 10;
	cout << " i:" << i << " j:" << j << endl;
	cout << "子线程运行结束" << endl;
	return;
}

int main() {
	int i = 5;
	int j = 8;
	std::thread T(test, i, j);
	T.join();
	cout << " i:" << i << " j:" << j << endl;
	cout << "主线程执行完毕" << endl;
	return 0;
}

image.png 我们可以看到线程 T 在执行时,是把数值拷贝到子线程中,并不是与主线程共用一份数据,这是最简单的一种传递方式

2、通过引用的方式

void test(int i,int j,std::string const &s) {
	cout << "子线程运行 start" << endl;
	i = i + 10;
	j = j + 10;
	cout <<"子线程变量地址" <<&s<< endl;
	cout << " i:" << i << " j:" << j << endl;
	cout << "子线程运行结束" << endl;
	return;
}

int main() {
	int i = 5;
	int j = 8;
	string name = "hello";
	cout << "主线程地址" << &name << endl;
	std::thread T(test, i, j, name);
	T.join();
	cout << " i:" << i << " j:" << j << endl;
	cout << "主线程执行完毕" << endl;
	return 0;
}

image.png 我们可以很明显的看到在子线程和主线程的地址是不一样的,再一次说明了子线程是将变量拷贝一份到子线程中,但是这里我们是使用const 不能修改引用的值,如果我们在里面调用s.append()是会报错的,因此我们需要使用std::ref来出来,如下所示

void test(int i,int j,std::string &s) {
	cout << "子线程运行 start" << endl;
	i = i + 10;
	j = j + 10;
	s.append("hello");
	cout <<"子线程变量地址" <<s<<"----" << &s << endl;
	cout << " i:" << i << " j:" << j << endl;
	cout << "子线程运行结束" << endl;
	return;
}

int main() {
	int i = 5;
	int j = 8;
	string name = "hello";
	cout << "主线程地址" << &name << endl;
	std::thread T(test, i, j, std::ref(name));
	T.join();
	cout << " i:" << i << " j:" << j << endl;
	cout << "主线程执行完毕" << endl;
	return 0;
}

image.png 通过这种方式我们可以发现,主线程和子线程的变量地址是一样,这种就类似下面下面3 指针的传递很类似 那么为什么要使用std::ref(name) 这种方式呢,因为我们知道,线程在开启后,主线程还是会继续往下执行的,可能在下一步前面的变量就已经销毁了,因此可能出现野指针的情况,那么我们使用std::ref(name)将name在传进去就转换了,就相当于指针的形式,我估计这里很多人很难理解这其中的原因,如果不用ref 那么name会隐式的转换,复制一个引用传递给另外一个引用,可能还没来得及转换成功就已经失败了,那么使用ref就相当于这一步还在主线程中执行,那么肯定会成功的(如果解释有误,请大佬评论留言)

3、通过指针的方式

void test(int i,int j,std::string *s) {
	cout << "子线程运行 start" << endl;
	i = i + 10;
	j = j + 10;
	s->append("hello");
	cout <<"子线程变量地址" <<*s<<"----" << s << endl;
	cout << " i:" << i << " j:" << j << endl;
	cout << "子线程运行结束" << endl;
	return;
}

int main() {
	int i = 5;
	int j = 8;
	string name = "hello";
	cout << "主线程地址" << &name << endl;
	std::thread T(test, i, j, &name);
	T.join();
	cout << " i:" << i << " j:" << j << endl;
	cout << "主线程执行完毕" << endl;
	return 0;
}

image.png 通过指针的方式可以看到,指针的地址并没有改变

4、通过成员函数的形式

C++线程传递参数可以将类的成员函数传递作为线程的执行函数例如下面所示

class Person {

public:
	Person() {}
	Person(string name) {}
	~Person() {}
	void eatFood(string na) {
		cout << "执行:" << na << endl;
	}
private:
	string name;
};


int main() {
	int i = 5;
	int j = 8;
	string name = "hello";
	Person person;
	std::thread T(&Person::eatFood,&person,name);
	T.join();

	return 0;
}

image.png