我最近在一次采訪中被問到這個問題。問題是我們是否有一個函式將 int 的參考i作為引數并且只做i . 沒有任何執行緒同步。現在在main函式中,我們用 0 初始化變數i,然后我們創建 7 個新執行緒來運行相同的函式并傳遞相同的變數i,在所有執行緒加入之后,變數i有多少可能的值?非常感謝!
我試著思考做的指示i 。像load,add和store說明。假設我們正在使用g 編譯器并在 Linux 作業系統中。
uj5u.com熱心網友回復:
您描述的代碼具有未定義的行為。的值i未定義。如果您確實編譯并運行代碼并i在螢屏上列印,則輸出可能是任何內容。它可能是42或"hello world"。
也許這個問題是為了讓您考慮有多少種不同的方式來增加多個執行緒i以及這會如何影響輸出。但是,當代碼具有未定義的行為時,邏輯推理是徒勞的。
另一方面,如果您關心編譯代碼中實際發生的情況,那么了解這一點的唯一方法就是查看編譯器生成的程式集。結果程式所做的是未定義的,但它肯定會做一些事情。盡管您只能在編譯并研究程式集之后才能知道那是什么。C 標準沒有描述這樣的程式將做什么以及你得到的任何東西都是不可移植的。
uj5u.com熱心網友回復:
如其他答案所述,有UB。
此外,可能會出現此數字根本不增加或增加幾次(小于 7)或其他任何情況的情況。由于它不是原子變數(問題沒有提到) - 它會產生非常不穩定/不可預測的結果。有關更多解釋,請參閱/google 以獲取“記憶體模型”。
uj5u.com熱心網友回復:
用于增加變數的具體指令取決于指令集,但除非使用某種原子增量,否則它將分解為您所描述的加載/添加/存盤操作。在 x86 上,這可以用一條inc指令完成,但沒有鎖定它仍然會分解為內部加載/添加/存盤操作。
您將需要查看這些序列的可能交錯。交織是由非原子序列的中斷引起的。這是一種可能的這種可能的交錯:
thread 1 thread 2
load
load
add
store
add
store
該序列將使變數僅由執行緒 1 遞增一次,因為執行緒 2 的遞增操作實際上被忽略了——執行緒 1 最后存盤,因此“獲勝”。(無論如何,執行緒 2 以某種意義上的錯誤值開始,因此執行緒 2 的存盤與執行緒 1 的存盤具有相同的值( 1)。)
因此,在一個極端情況下,答案是變數只會增加一。在另一個極端,如果每個執行緒成功遞增而不中斷該序列,則變數將遞增 7 次。所有中間值(增加 2-6)也是可能的。
由于根本沒有同步,我們還必須考慮在加入后觀察到原始 0 的可能性,盡管我認為這不太可能,因為創建執行緒和加入執行緒時涉及的系統呼叫的自然同步。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/455265.html
