2016-08-09 19 views
0

我有一個帶有兩個線程的單核CPU(ARM Cortex M3,32位)。假設以下情況:是在單核CPU原子上寫入變量嗎?

// Thread 1: 
int16_t a = 1; 
double b = 1.0; 
// Do some other fancy stuff including starting Thread 2 
for (;;) {std::cout << a << "," <<b;} 

// Thread 2: 
a = 2; 
b = 2.0; 

我可以處理以下輸出:

  • 1,1-
  • 1,2-
  • 2,1
  • 2,2-

我可以肯定,輸出將永遠是那些(1/2)之一,而不使用mutex或其他鎖定機制?更具體地說,這個編譯器是依賴的​​嗎? int16double的行爲有何不同?

+3

對_atomic_訪問使用'std :: atomic '。 –

+2

您的代碼具有完全可移植性和獨立於編譯器的*未定義行爲*。所有的實現都可以完全自由地做任何他們想做的事情。 –

+0

@πάνταῥεῖ。不幸的是,由於編譯器的限制,我無法訪問它(例如,沒有C++ 11)。但除此之外,這將是一條路。 –

回答

2

這取決於CPU,主要是,雖然在預C11涉及多個線程理論什麼是最好的實現定義,在最壞的情況不確定的行爲,因此編譯器可能會做任何事情。

如果你可以忽略瘋狂的編譯器做愚蠢的事情,並假定編譯器將使用CPU的設施,以合理的方式,它主要取決於什麼CPU的支持。

Cortex-M3的是一個32位CPU,一個32位總線和沒有FPU。因此讀取和寫入32位和更小的值通常是原子的。然而,double是64位的,所以任何雙/雙寫操作都會涉及兩條指令並且是非原子的。因此,如果一個線程讀取而另一個線程讀取,則可能會從一個值減半,而另一個值減半。

現在在你的具體的例子,值1.0和2.0是其下半部分都是0,所以「混合」是無害的,但其他的值不會有這種行爲。

+0

我現在很困惑。如果我堅持兩個32位或更低的文字是原子? (不受任何標準保證,但在實踐中) –

+0

實際上,是32位和更小的整數將是原子。當然,對多元變量的訪問可能會重新排序,除非您在它們之間粘貼(編譯器特定的)屏障。 –

+0

我一直認爲32位是對記憶地址大小的引用。這意味着可以處理2^32位。這是否也構成可尋址內存大小塊的下限? –

1

該操作的評估順序爲:不保證從左到右,即使它們是,它們不是原子的,如果你嘗試讀取和寫入同時發生段錯誤(它們可以執行多個週期並且上下文切換可以打斷它)。

在arm上,特別是讀取和寫入在cpu上的隊列中,它們可以自由地重新排序(除去過去的內存障礙),即使在不重新排序內存的cpu上,編譯器也可以自由地重新排序。沒有任何東西阻止你的任務,並且閱讀被向前或向後移動,所以你不能保證任何值或順序的狀態。

相關問題