如何傳遞參數(shù)?
void f(int i, std::string const& s);
std::thread t(f, 3, "hello");
【注意】 默認(rèn)參數(shù)是拷貝到線程獨(dú)立內(nèi)存中的,以便新線程在執(zhí)行中可以訪問(wèn),即使參數(shù)是引用的形式。
特別注意,當(dāng)指向動(dòng)態(tài)變量的指針作為參數(shù)傳遞給線程的情況
void f(int i,std::string const& s);
void oops(int some_param)
{
char buffer[1024]; // 1
sprintf(buffer, "%i",some_param);
std::thread t(f,3,std::string(buffer)); // 使用std::string,避免懸念
t.detach();
}
成功的傳遞一個(gè)引用,會(huì)發(fā)生在線程更新數(shù)據(jù)結(jié)構(gòu)時(shí)。
void update_data_for_widget(widget_id w,widget_data& data); // 1
void oops_again(widget_id w)
{
widget_data data;
std::thread t(update_data_for_widget,w,data); // 2
display_status();
t.join();
process_widget_data(data); // 3
}
update_data_for_widget的第二個(gè)參數(shù)期待傳入一個(gè)引用,但是std::thread的構(gòu)造函數(shù),不知道這件事,構(gòu)造函數(shù)無(wú)視函數(shù)期待的參數(shù)類(lèi)型,并且盲目拷貝已提供的變量。當(dāng)線程調(diào)用update_data_for_widget函數(shù)時(shí),傳遞給函數(shù)的參數(shù)是data變量?jī)?nèi)部拷貝的引用,而非數(shù)據(jù)本身的引用。當(dāng)線程結(jié)束時(shí), 內(nèi)部拷貝數(shù)據(jù)將會(huì)在數(shù)據(jù)更新階段被銷(xiāo)毀,且process_widget_data將會(huì)接收到?jīng)]有修改的data變量。
解決這個(gè)問(wèn)題:使用std::ref將參數(shù)轉(zhuǎn)換成引用的形式:
std::thread t(update_data_for_widget, w, std::ref(data));
可以傳遞一個(gè)成員函數(shù)指針作為線程函數(shù), 并提供一個(gè)合適的對(duì)象指針作為第一個(gè)參數(shù):
class X
{
public:
void do_lengthy_work();
};
X my_x;
std::thread t(&X::do_lengthy_work,&my_x);
也可以為成員函數(shù)提供參數(shù):std::thread構(gòu)造函數(shù)的第三個(gè)參數(shù)就是成員函數(shù)的第一個(gè)參數(shù):
class X
{
public:
void do_lengthy_work(int);
};
X my_x;
int num(0);
std::thread t(&X::do_lengthy_work, &my_x, num);
一個(gè)有趣的地方是:
提供的參數(shù)可以是“移動(dòng)的”,但不能是“拷貝”。這里的移動(dòng)是指原始對(duì)象中的數(shù)據(jù)轉(zhuǎn)移給另一對(duì)象, 而轉(zhuǎn)移的這些數(shù)據(jù)就不再在原始對(duì)象中保存了。
下面的代碼展示了std::move的用法,它是如何轉(zhuǎn)移一個(gè)動(dòng)態(tài)對(duì)象到一個(gè)線程中去的:
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));