[C++11 并发编程] 03 - 向线程传递参数

我们可以通过std::thread的构造函数向线程传递参数,但是默认情况下,这些参数的拷贝会被传递到线程内部,即使参数申明为引用,也是如此:

void f(int i,std::string const& s);
std::thread t(f,3,"hello");
如上面例子所示,创建了一个线程关联到t,它会调用f(3, "hello"),虽然f的第二个参数类型为std::string,但是实际上字面量hello还是以char const *类型传递到线程内部,再在新的线程上下文内被转换回std::string。
这样,如果我们为传递给线程的是一个临时变量,新线程在将这块buffer转换为std::string前,拥有这块buffer的函数就退出了,就会导致新的线程出现问题。这个问题的解决办法是在将buffer传递给std::thread构造函数时,就将其类型转换为std::string:

void f(int i,std::string const& s);
void not_oops(int some_param) {
	char buffer[1024];
	sprintf(buffer,"%i",some_param);
	std::thread t(f,3,std::string(buffer));
	t.detach();
}
另一种情况是我们希望将一个结构实例的引用传递给一个线程,新的线程在其执行过程中更新和修改这个结构:

void update_data_for_widget(widget_id w,widget_data& data);
void oops_again(widget_id w)
{
	widget_data data;
	std::thread t(update_data_for_widget,w,data);
	display_status();
	t.join();
	process_widget_data(data);
}
update_data_for_widget期望第二个参数以引用的方式传递给新的线程,但是std::thread的构造函数并不知道这个需求,它只是将这个结构拷贝一份,传递给新的线程。当update_data_for_widget执行时,它会将拷贝的引用传递给自己,而不是外部的那个data实例的引用,这就导致,线程执行结束,只是修改了data的拷贝,而data本身则没有任何变化。
这种情况下,我们需要使用std::ref来使data的引用被正确的传递给update_data_for_widget。
std::thread t(update_data_for_widget,w, std::ref(data) );
还有一种情况是,有些参数不能被拷贝但是可以被移动(move),对象中的数据被转移给另一个对象,之前对象中的数据将被清空。比如,std::unique_ptr,这个类型用于管理动态分配的对象。在同一时刻,只有一个std::unique_ptr的实例可以指向一个特定的对象,当指针被销毁时,其所指向的对象也将被销毁。move构造函数和move赋值运算符使得我们可以在std::unique_ptr实例之间传递对象的所有权。
下面这个例子则是使用std::move来将动态对象的所有权传递给一个线程:

void process_big_object(std::unique_ptr<big_object>);

std::unique_ptr<big_object> p(new big_object);
p->prepare_data(42);
std::thread t(process_big_object,std::move(p));
std::thread构造函数中调用std::move(p)使得big_objects的所有权被传递给新创建线程的内部,然后被传递给process_big_object方法。

可移动(movable)但是不可拷贝(copyable)使得我们可以保证,同一时刻,只有一个对象与一个特定的线程关联,而我们可以在对象之间传递线程的所有权。


已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页