C 執行緒的引數傳遞 值傳遞和引用

2021-08-21 08:46:09 字數 1669 閱讀 8594

前言

執行緒一般通過複製或引用獲取其資料。

預設情況下,您應該用乙個副本。

為啥呢?如果您的執行緒通過引用獲取其資料,那得非常小心引數的生命週期。

執行緒引數

執行緒是可變引數模板。所以它可以獲得任意數量的引數。

現在咱們來看看通過複製或引用獲取引數之間的區別:

std::string s

std::thread t([=]

);t.join();

std::thread t2([&]

);t2.detach();

準確地說,在這個例子中,獲取引數的不是執行緒,而是lambda函式。

因此第乙個執行緒t1獲取的是副本的資料([=]),第二個執行緒t2通過引用([&])獲取其資料。

其中隱藏著什麼危險?

執行緒t2通過引用獲取其字串s後就從其建立者的生命週期中分離了。

一方面,字串的生命週期繫結到呼叫上下文的生命週期;另一方面,全域性物件std::cout的生命週期繫結了主線程的生命週期。

因此,可能會發生字串s的生命週期或std::cout的生命週期還沒執行緒t2的生命週期長。現在我們處於未定義行為的坑中。。。。。。。。

你還不信?那咱們瞅瞅未定義的行為可能是什麼樣子:

// threadarguments.cpp

#include

#include

#include

class sleeper

{};void

operator() (int k)

std::cout

<< std::this_thread::get_id() << std::endl;

}private:

int& i;

};int main()

首先,valsleeper算是main中的乙個全域性變數。

sleeper是個函式物件以及變數成員變數值為valsleeper和還有(int k)傳入數字5。

關鍵的問題是,執行緒是通過引用得到valsleeper,並將其從主線程的生命週期中分離出來。然後它將執行函式物件的呼叫操作符()。

在該方法中,它從0到5計數,在每次迭代中休眠100毫秒並且將i+=k。

最後,它在螢幕上列印其id。

理論上執行完之後,結果必須是1000 + 6 * 5 = 1030。

但是,發生了什麼?有些事情是完全錯誤的!!

有兩個問題:其一,valsleeper是1000,其二,控制台上沒有id。

所以,這就是未定義的行為。原因在於子執行緒執行計算或將其id列印在std ::cout之前,主線程的生命週期結束。

如果主線程通過t.join()等待,直到這個子執行緒完成它的工作,我們得到預期的結果:

Python引數傳遞 引用傳遞 值傳遞

值傳遞 方法呼叫時,實際引數把它的值傳遞給對應的形式引數,方法執行中形式引數值的改變不影響實際引數的值。a1 520 a2 a1 print a1 520 print a2 520 a2 a1 1 print a2 521 print a1 520 引用傳遞 也稱位址傳遞,在方法呼叫時,實際上是把引...

C 值傳遞和引用傳遞

概念 在定義函式時函式括號中的變數名成為形式引數,簡稱形參或虛擬引數 在主調函式中呼叫乙個函式時,該函式括號中的引數名稱為實際引數,簡稱實參,實參可以是常量 變數或表示式。注意 c語言中實參和形參之間的資料傳遞是單向的值傳遞。被呼叫函式的形參只有函式被呼叫時才會臨時分配儲存單元,一旦呼叫結束占用的記...

1 3 5傳遞引數之值傳遞和引用傳遞

先把最重要的一句話放在前面 通常向方法傳遞乙個實參時,對應的引數 形參 會用實參的乙個副本來初始化。1 引用傳遞 首先是傳遞引用型別的引數 2 值傳遞 其次是傳遞值型別的引數 using system namespace test changea a1 console.writeline a1的值為...