一:傳遞臨時對象作爲線程參數
1.1、要避免的陷阱1(解釋1)
1.2、要避免的陷阱2(解釋2)
class A
{
public:
mutable int m_i; //const下也能修改
//類型轉換構造函數
A(int a):m_i(a){cout<<"構造函數執行"<<this<<"threadid="<<std::this_thread::get_id()<<endl;}
A(const A &a):m_i(a.m_i){cout<<"拷貝構造函數執行"<<this<<"threadid="<<std::this_thread::get_id()<<endl}
~A(){cout<<"析構函數執行"<<this<<"threadid="<<std::this_thread::get_id()<<endl;}
void thread_work(int num) //來個參數
{
cout<<"子線程thread_work執行"<<this<<"thradid="<<std::this_thrad::get_id()<<endl;
}
void operator()(int num)
{
cout<<"子線程()執行"<<this<<"thradid="<<std::this_thrad::get_id()<<endl;
}
};
//void myprint(const int &i, char *pmybuf)
void myprint(const int &i, const string &pmybuf) //感覺可行其實還是不行
{
cout<<i<<endl; //分析認爲,i並不是mvar的引用,實際是值傳遞,那麼我們認爲,即使主線程detach了子線程,那麼子線程中用i仍然是安全的。
cout<<pmybuf.c_str()<<endl; //指針在detach子線程時,絕對會有問題
cout<<*pmybuf<<endl;
return;
}
void myprint(const int i, const A&pmybuf)
{
cout<<&pmybuf<<endl; //打印地址
}
//void myprint2(const A &pmybuf)
void myprint2(unique_ptr<int> pzn)
{
pmybuf.m_i = 199;//我們修改該值不會影響main函數
cout<<"子線程myprint2的參數地址是"<<&pmybuf<<"threadid="<<std::this_thread::get_id()<<endl;
}
int main()
{
int mvar = 1;
int &mvary = mvar;
char mybuf[] = "this is a test!";
thread mytobj(myprint,mvar,mybuf);//但是mybuf到底是在什麼時候轉成string.
//事實上存在,mybuf都被回收了(main函數執行完了),系統才用mybuf去轉string
thread mytobj(myprint,mvar,string(mybuf));//這裏直接將mybuf轉換成string對象,這是一個可以保證在線程中用肯定有效的對象
//mytobj.join();
//1.2
int mvar = 1;
int mysecondpar = 12;
thread myobj(myprint, mvar, A(mysecondpar));//我們是希望mysecondpar轉成A類型對象傳遞給myprint的第二個參數
//在創建線程的同時構造臨時對象的方法傳遞參數是可行的;
//mytojb.join;
cout<<"主線程id是"<<std::this_thread::get_id()<<endl;
int myar = 1;
std::thread myobj(myprint2, A(mvar)); //這樣顯示轉換是安全的
A myobj(10); //生成一個類對象
std::thread myobj(myprint2, myobj);//myobj將類對象作爲線程參數
unique_ptr<int> myp(new int(100));
std::thread mytobj(myprint2, std::move(myp));
//用成員函數指針做線程函數
A myobj(10); //生成一個類對象
std::thread myobj(&A::thread_work, myobj, 15);//&myobj==std::ref(myobj)
mytobj.join(); //用成員函數必須用join
//用()作爲線程入口函數
A myobj(10); //生成一個類對象
std::thread myobj( myobj, 15);//&myobj==std::ref(myobj)//用std::ref後就不調用拷貝構造函數了,那麼後續如果調用mytobj.detach()就不安全了;
mytobj.join();
mytobj.detach(); //子線程和主線程分別執行。
cout<<"I Love China!"<<endl;
return 0;
}
1.3、總結
a、若傳遞int這種簡單類型參數,建議都是值傳遞,不要用引用。防止節外生枝。
b、如果傳遞類對象,避免隱式類型轉換。全部都在創建線程這一行就構建出臨時對象來,然後在函數參數裏,用引用來接,否則系統還會多構造一次臨時對象
c、建議不使用detach(),,只使用join();這樣就不存在局部變量失效導致線程對內存的非法引用問題;
二:臨時對象作爲線程參數繼續講,常用測試大法;
2.1、線程id概念:ID是個數字,每個線程(不管是主線程還是子線程)實際上都對應着一個數字,而且每個線程對應的數字都不同。也就是說,不同的線程,它的線程id(數字)必然是不同;
線程id可以用C++標準庫裏的函數來獲取。std::this_thread::get_id()來獲取。
2.2、臨時對象構造時機捕獲
三:傳遞類對象作爲線程參數
正常子線程下修改類成員變量不會影響主線程類成員變量,不管有沒有引用在線程都以拷貝接收類對象
用std::ref可以使對象真正傳引用