2010-07-28 25 views
5

我知道如何在x86 ASM中原子地寫入一個值。但是我怎麼讀一個? LOCK前綴不能與mov一起使用。如何自動讀取x86 ASM中的值?

要增加的值,我做:

lock inc dword ptr Counter 

如何在一個線程安全的方式讀取計數器?

回答

4

我不是裝配專家,但字大小(在x86,32位)讀/寫應該是原子已經。

您需要鎖定增量的原因是因爲這既是讀取又是寫入。

+0

我認爲你是對的。這就說得通了。謝謝。 – IamIC 2010-07-28 04:12:46

+0

不要忘了接受一個答案,如果它幫助你;) – 2010-07-28 04:20:12

+4

並不總是!如果內存地址在使用多CPU單元中的第二個CPU的高速緩存中,則讀數不保證是原子的。因此,使用「LOCK CMPXCHG EAX,[var]」,它首先圍繞內存緩存。 – 2010-07-28 06:03:58

1

對於簡單的閱讀,主要是關於對齊。確保原子讀數的最簡單方法是始終使用「自然」對齊 - 即對齊至少與項目大小一樣大(例如,32位項目是32位對齊)。

未對齊的讀取不一定是原子。舉一個極端的例子,考慮在第一個字節在一個緩存行中的奇數地址處讀取一個32位值,其他三個字節在另一個緩存行中。在這種情況下,原子讀取基本上是不可能的。由於(至少大多數)處理器使用64位寬的存儲器總線,所以希望被原子讀取的最大項目是64位。

5

正如我在this後向你解釋:

訪問緩存的內存是跨越總線帶寬,高速緩存行, 和頁面邊界,不能保證 由英特爾酷睿2是原子 分裂Duo, Intel Core Duo,Pentium M,Pentium 4, Intel Xeon,P6系列,Pentium和 Intel486處理器。 Intel Core 2 Duo,Intel Core Duo,Pentium M, Pentium 4,Intel Xeon和P6系列處理器提供總線控制信號 ,允許外部存儲器子系統 使分割訪問原子化;然而,非對齊的數據訪問將會嚴重影響處理器的性能,應該避免。

所以使用:

LOCK  CMPXCHG EAX, [J] 

LOCK CMPXCHG第一柵欄高速緩衝存儲器和比比較目標值的EAX,如果目標值不EQU那麼結果在EAX是目標值。

編輯: 鏈接:

Intel® 64 and IA-32 Architectures Software Developer’s Manuals

Volume 3A: System Programming Guide檢查8.1.1節

同時檢查:Optimization Reference Manual section: CHAPTER 7 OPTIMIZING CACHE USAGE

+0

因爲[J]是內存指針,所以不會編譯。它必須是一個註冊值。這是我無法解決的問題。 – IamIC 2010-07-28 15:40:52

+1

我從你的另一篇文章中看到,只要值與CPU的總線寬度一致,這實際上不是問題。 – IamIC 2010-07-28 15:53:07

+0

@IamIC:完全不是總線寬度。英特爾和AMD保證的最低公分母是'mov'加載/存儲是原子的(如果它不跨越8字節邊界(對於緩存訪問)。](https://stackoverflow.com/a/36685056/224132)或者對於未緩存的,如果對齊或者不跨越雙字邊界的16位訪問。另外'[J]'是一個絕對的或(在x86-64中)一個RIP相對尋址模式。這不是雙重間接。它組裝得很好。 MASM語法通常會忽略'[]',但它們在MASM中是可選的,並且在NASM中是必需的。 – 2018-01-01 01:42:18

1

有趣的是,閱讀對方回覆。我認爲@GJ可能就是這筆錢。

多年來,32位讀寫是原子總是如此。只有在最近幾年,真正積極的緩存才能保證這一點。

我想這就是爲什麼我更喜歡C++,Java或其他類似於我和機器代碼之間的原因。這些天機器代碼太複雜,無法可靠地寫入(除非你這樣做)。很多保持你的技能銳利)。幸運的是,今天的優化編譯器非常好,所以你很少需要手動優化彙編器的性能。

+0

C++不會保證有關CPU的內存語義的任何內容,也不會保證Java沒有volatile。 – 2012-08-27 07:46:55

+0

與C(C11)一樣,C++可以保證原子類型(C++ 11的東西)的原子訪問。 – 2014-06-03 13:51:48