2017-02-27 87 views
0

作爲一個業餘愛好項目,我正在用垃圾收集來創建一種編程語言。 該語言將被編譯爲(最好是可移植的)C++並支持線程。線程可以混合寫入值嗎?

現在的問題是: 支持兩個線程「同時」將不同的值寫入同一個(指針大小和對齊的)內存位置。 那麼是否有可能讓任何線程讀取兩個值之間的混合?

例如在32位平臺上:

線程1條寫道:AAAAAAAA

線程2條寫道:BBBBBBBB

將任何線程總是讀AAAAAAAA或BBBBBBBB也可以讀取AAAABBBB或其他一些兩者之間的「混合」? 我不關心訂購和最終價值。重要的是,從該位置不能讀取任何無效值。

我意識到這可能取決於平臺,C++可能不會提供任何承諾。 對於某些平臺會有保證嗎?是否需要使用內聯彙編器來實現? PS:我相信std :: atomic會做出這樣的保證,但是我認爲使用所有加載/存儲操作來處理對象引用會有很大的開銷。

+1

如果您正在編寫以空字符結尾的字符串並且尚未附加終止字符,該怎麼辦?你可能不想混合讀寫。 – AndyG

+2

作爲一個語言設計者,它定義了數據競賽發生時會發生的事情。你可以決定一個實現必須以某種方式處理它(限制性能),或者你可以決定底層硬件決定發生了什麼(而不是平臺獨立),或者任何事情都是可能的(很難編程在)。問我們你的語言如何在某種情況下表現得沒有意義。 – nwp

+0

我在問C++的行爲,因爲我打算編譯爲C++。我知道C/C++有很多未定義的行爲,所以我的問題是如何在C++中實現「從不讀取無效指針」的保證。 – LaZe

回答

1

C++沒有這樣的保證,它取決於硬件。 典型的硬件/處理器,如Arm,x86,amd64,只要寫入是32位對齊的,那麼32位讀寫操作將是原子的。

每次讀/寫32位一個字節(比如strcpy,memcpy等),所有的注單都關閉 - 很大程度上取決於這些函數的實現(它們傾向於獲得很多優化)。

當存在多個內存位置時,它在某些平臺上變得更加複雜。

說你有

extern int32 a; 
extern int32 b; 

a = 0x12345678; 
b = 0x87654321; 

現在,單獨,A和B是由線程1寫入原子,但觀察員,線程2,可以 「看到」 A.

前b變動的價值

這可能由於硬件和軟件而發生。 軟件(C++編譯器/優化器)可能會重新排列代碼,如果它認爲它會更好。 (或者,編譯器甚至可能避免在某些情況下將值寫入a和b)。

硬件還可以在運行時重新安排內存讀/寫 - 當thread1和thread2在不同內核上運行時可見,並且直到core1執行某些操作才能將內部內存管道與系統其餘部分同步,core2可能會看到有些不同。對於這些優化,Ia64非常積極。 X86並沒有太多(因爲它會打破我假設的太多遺留代碼)。

在C/C++中,「volatile」基本上可以讓你告訴編譯器在這個變量周圍進行優化的時候不那麼積極 - 儘管它確實取決於實現。通常這意味着編譯器不會優化讀/寫易失變量,並且通常不會重新排列對它們的訪問。

這不會改變處理器在運行時可能會發生的情況。爲此,您需要使用特殊的「內存障礙」內隱/操作。 這些細節很複雜,通常隱藏在諸如「原子」之類的東西之後。噢,也是,大多數系統都有神奇的內存 - 某些地址由硬件保留用於特殊目的。通常情況下,除非你正在編寫設備驅動程序,否則不會遇到這種情況

+0

嗨,你好,謝謝你闡述這個問題。 – LaZe

相關問題