C++:多线程中的小白(3)线程传参详解
(1)傳遞臨時對象作為線程參數
(2)傳遞類對象智能指針作為線程參數
(3)用成員函數指針做線程函數
在實際工作中我們要創建的線程可能不止一個,比如說我們要創建10個,編號從0到9,這10個線程會根據自己的編號確定自己要干的事情,這個線程如何知道自己的編號呢,這個就需要我們給線程傳遞參數(比如我們傳遞0123456789這10個數,那么線程就通過接收的這個參數就知道自己的編號了。)。
void myprint(const int &i,char *pmybuf)
{cout<<i<<endl;cout<<pmybuf<<endl;}
int main()
{//傳遞臨時函數作為線程參數int mvar=1;int &mvary=&mvar;char mybuf[]=“this is a test”;//定義一個字符數組
//thread創建一個mytobj的對象
thread mytobj(myprint,mvar,mybuf);//第一個參數傳遞的是線程函數名,第二個開始傳遞參數(該參數是線程函數的第一個參數)第三個創建這個對象構造函數的第三個參數就是線程函數myprint這個函數的第二個參數。(所以第一個參數就是線程函數,后邊第二、三個參數是這個線程函數的所有參數)mytobj.join();//等待子線程執行完畢cout<<"I Love China"<<endl;return 0;}
運行結果:
傳進去的參數分別是1和this is a test!
上述要注意的問題1是:
假如我上邊沒有使用join,使用的是detach(),主線程和子線程分別執行自己的。那么有可能主線程先執行完了(主線程執行完了也無所謂,子線程在后臺繼續執行。)
上述我們看到了,子線程使用的參數是一個引用,mvar的一個引用,如果主線程先退出,那么mvar可能被系統回收了,那我們在子線程中用這個i的話會出問題嗎?(打印地址查看后經實驗雖然是安全的,但是不建議。)
三個的地址不一樣說明一個問題,我們在myprint里邊雖然使用的是引用,但是我們在創建thread對象Mytobj的時候,里邊的mvar并不是真的用mvar的引用來綁這個mvar的,實際這里邊他肯定是做了個復制,也就是說他是把mvar的值復制給了i,所以這個i不是一個真引用(因為i的地址跟mvar的地址不一樣,作為引用來講應該是一樣的但實際是不一樣的,所以說thread這個內部肯定做了一個復制,他把實際做的這個東西i不是一個引用(i并不是mvar的引用,實際是值傳遞,雖然myprint里邊是引用但是實際是值傳遞,因為i跟其他的地址不一樣),是一個值。所以說這里使用detach的話,雖然主線程可能先執行完,但是在子線程中因為i不是一個真引用,是一個復制的值,所以我們在子線程中用i應該是安全的(因為子線程中你用的并不是mvar值,是自己復制出來的一個值,所以是安全的),但是也不建議這么寫)。
再看子線程中的第二個參數是否安全:
說明pmybuf指向的是mybuf的地址,那如果用detach運行的話,當主線程main函數先運行完了,內存就被系統回收了,那你在子線程中再使用這個指針就不安全了。如果要用detach參數創建線程的話,不推薦用引用,不推薦用指針(指針在detach子線程時絕對有問題的)。
怎么樣將這個字符串mybuf傳遞到線程中來呢?
//將上邊myprint函數做修改
void myprint(const int i,const string &pmybuf)
{cout<<i<<endl;cout<<pmybuf.c_str()<<endl;}
int main()
{//傳遞臨時函數作為線程參數int mvar=1;int &mvary=&mvar;char mybuf[]=“this is a test”;//定義一個字符數組thread mytobj(myprint,mvar,mybuf);mytobj.join();//等待子線程執行完畢cout<<"I Love China"<<endl;return 0;}
地址查看:
上述要注意的問題2是:
thread mytobj(myprint,mvar,mybuf);//啟動這個線程的話,我們希望是將mybuf字符數組轉化成隱式字符串,然后我們在string中就可以使用string這個對象,這樣的話線程就不會引用主線程也就是main函數中mypuf這段內存,那你mybuf這段內存,如果你主線程運行完了,銷毀了這段內存,也不會影響我pmybuf內存的引用。但現在的問題是mypuf在什么時候轉化為string?比如我這個mian函數都執行完了你才把mypuf往string轉,那就太尷尬了,此時mupuf已經被系統回收了(因為mybuf是一個局部變量,屬于主線程中的變量),回收了就沒有辦法轉了。
需要將主函數中代碼修改為:
thread mytobj(myprint,mvar,string(mybuf));//這里直接將mypuf轉化成string對象,這是一個可以保證在線程中肯定有效的對象
使用mybuf臨時構造了一個string對象,然后這個string對應myprint中的第二個參數string。為什么轉化成臨時的string對象就沒有問題了呢?
class A
{
public:int m_i;A(int a):m_i(a){cout<<"A::A(int a)構造函數執行<<endl;"}//帶一個參數的構造函數A(const A &a):m_i(a.m_i){cout<<"A::A(const A &a)構造函數執行<<endl;"}//拷貝構造函數}
void myprint(const int i,const A &pmybuf)
{cout<<&pmybuf<<endl;//這里打印的是pmybuf的地址return;
}
int main()
{int mvar=1;int mysecondpar=12;thread mytobj(myprint,mvar,mysecondpar);//我們希望mysecondpar轉化成A類型對象傳遞給myprint的第二個人參數
//改造一下thread mytobj(myprint,mvar,A(mysecondpar));
}
上述在主線程結束之前,pmybuf一定是已經構造出來了,在這個值還是有效的時候我就已經構造出來了a對象傳遞到線程中去了,現在A對象就被保存到了pmubuf
總結
以上是生活随笔為你收集整理的C++:多线程中的小白(3)线程传参详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++:报错解决合集
- 下一篇: C内存2:内存分区