天天看點

三、線程傳參

引用和指針:

陷進一:不要用引用和指針,因為位址可以被主線程運作完後釋放了。

陷阱二:将對象傳遞給子線程時,可能主線程都運作完了,對象還沒建構。

通過源碼可知,thread類禁用了拷貝構造函數,但支援對象move

帶參架構函數接受的值是右值引用。非帶參和move的線程都是非joinable的。

指針變量如果用detach,很可能主線程結束了,子線程讀取指針變量發生錯誤。

都是右值引用,為什麼int安全,int*類型不安全:

主線程中的i=1和int *p在傳參時應該都是傳的臨時值。

int* && pp=p後,其實最終通路的資料還是i,如果 i 釋放了,那麼p的副本pp也會通路失敗。

int& i;由于子線程不接受左值,主線程會根據左值生成臨時值,然後右值引用=臨時值。

三、線程傳參

  右值引用就是對臨時對象的引用,右值引用在臨時對象釋放後,還是能更改右值引用所引用的值。下面的代碼就是主線程負責申請臨時空間,然後通過右值引用拿來用。

  string& pmybuf=string(mybuf):

  通過上面分析,首先得到 pmybuf 的副臨時對象,然後把 pmybuf 副本轉換為右值引用。就類似函數參數要求int ,但傳過來的是double。

id是個數字,每個線程實際上都對應着一個數字,而且每個線程對應的數字都不同,也就是說不同的線程id必然是不同的;

線程id可以通過c++标準庫裡的函數來擷取。std::this_thread::get_id().

thread類直接包裝了一個pthread_t,在linux下實際是unsigned long int。

用了一個std::unique_ptr來包裝使用者定義的線程函數:

如果thread()中的參數不是線程函數需要的類對象,

運作結果:

三、線程傳參

 由此可知,類型轉換是在線上程中進行的(之前的分析也推出這個結論),那麼久帶來了一個問題:

  主線程已經吧var的臨時對象給子線程了,但是子線程還沒構造a對象(比如時間片還沒輪到子線程),主線程久執行完了,那臨時對象也肯定會銷毀,這種情況就會導緻程式異常。

  為什麼不讓子線程生成臨時對象呢:也就是可能子線程的時間片還沒到,沒機會生成臨時對象。(其實是我猜的)

修改代碼:

三、線程傳參

主線程:

   構造函數:将var轉換成a類;拷貝構造:根據a生成a的臨時對象;

子線程:

  const a& a=臨時a對象後:const a& 可以接受左值引用也可以接受右值引用

 如果參數不用const a&,會調用兩次a的拷貝構造函數,子線程會多調用一次拷貝構造函數。a a=臨時a對象。

上面代碼雖然傳遞的參數是引用,但是當它在子線程中執行時并不會影響主線程的變量。也就是說mybuf仍然是拷貝出來的,不是主線程傳遞對象的引用。

三、線程傳參
三、線程傳參

 在主線程中又執行了拷貝構造函數

增加std::ref()後 

三、線程傳參
三、線程傳參

心之所願,永不相忘

繼續閱讀