管理線程之向線程函數傳遞參數
阿新 • • 發佈:2017-08-06
track pan prepare dsm tac 變量 函數調用 char ref
在這樣的情況下,指針指向局部變量buffer,然後傳遞到新創建的線程。 這是,依賴buffer想std::string的隱式轉換,之後作為函數參數
雖然update_data_for_widget希望第二個參數用引用傳遞,可是std::thread的構造函數不知道,這是函數的參數會被拷貝。當調用update_data_for_widget時,會傳遞拷貝data的引用,而不是data的引用。當線程終止,線程內部的拷貝析構,可是函數process_widget_data傳遞的是未更新的data。對於熟悉std:bind的人來說,立即就能想到解決的辦法:你須要使用std::ref包裝參數。須要更改線程創建形式為:
向線程函數傳遞參數在構造線程對象時就可以完畢。可是要記住,默認情況下是把參數復制到線程內部,即使在函數中使用的是引用。比如
void f(int i,std::string const &s); std::thread t(f,3,"hello");上面代碼中,函數f的第二個參數是std::string,傳遞的是char const *會轉換為string。
當使用指針指向自己主動變量時。要特別註意:
void f(int i, std::string const& s); void oops(int some_param) { char buffer[1024]; sprintf(buffer,"%i",some_param); std::thread t(f,3,buffer); t.detach(); }
非常可能會發生函數oops已經終止。可是buffer還沒有轉換為std::string。這是buffer已經銷毀。解決辦法就是在傳遞之前就轉換:
void f(int i, std::string const& s); void 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); }
std::thread t(update_data_for_widget,w,std::ref(data));假設你熟悉std::bind,參數傳遞的語法就easy理解。
由於std::thread的構造函數和std::bind都是使用相同的原理。這也就是說,你能夠傳遞成員函數的指針作為函數參數,假如你使用對象指針作為第一個參數。
class X { public: void do_lengthy_work(); }; X my_x; std::thread t(&X::do_length_work,&my_x);上面代碼會在新線程調用my_x.do_lengthy_work()。由於my_x的地址作為對象指針。你也能夠提供參數比如成員函數調用:std::thread的第三個參數將會成為成員函數的第一個參數。
另一種情況是函數參數對象不能拷貝,僅僅能轉移其全部權(比如STL中的auto_ptr指針)。std::unique_ptr就是這種一個樣例。std::unique指針一次僅僅能指向一個對象。當指針析構時。對象也就被析構了。在賦值時是轉移全部權(像auto_ptr)。
在使用時,當對象是暫時對象時,會自己主動調用move,當是個變量時必須調用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));
管理線程之向線程函數傳遞參數