volatile和原子操作

2021-05-08 18:26:40 字數 2113 閱讀 9074

標  題: volatile和原子操作

時  間: thu aug  6 12:16:53 2009

點  擊: 26

所謂原子操作,就是"不可中斷的乙個或一系列操作" , 在確認乙個操作是原子的情況下,

多執行緒環境裡面,我們可以避免僅僅為保護這個操作在外圍加上效能昂貴的鎖,甚至借助

於原子操作,我們可以實現互斥鎖。

很多作業系統都為int型別提供了+-賦值的原子操作版本,比如 nt 提供了

interlockedexchange 等api, linux/unix也提供了atomic_set 等函式。

前兩天有同學問我:在x86上,g_count++ (int型別) 是否是乙個原子操作?  我的回答是

"不是的, 多個cpu的機器(smp)上面這就不是原子操作"。 

今天想起,在單cpu上這個是否是原子操作呢,但是這個和編譯器有關,編譯器可能有兩種

編譯方式:

a.  多條指令版本 , 這就不是原子的

mov 暫存器 , g_count

add  暫存器, 1

mov g_count , 暫存器

b. 單指令版本, 這在單cpu的x86上就是原子的

inc  g_count

只能寫程式驗證了, 讓5個執行緒每個對 g_count++ 一億次,假如是原子操作的話,結果應

該是5億:

其實還需要對 g_count 進行volatile宣告,防止編譯器對這裡不適當的優化,為了看看編

譯器對volatile的處理,我另外做了個volatile版本作為比較。

#include

#include

int g_count = 0;

dword winapi threadfunc( lpvoid lpparam )

#define thread_num 5

void main( void )

{dword dwthreadid;

handle hthread;

int i;

for (i=0;i0) 則繼續迴圈

終於發現了問題所在了, 優化以後,迴圈從i++變成了i--, 就是如下的形式:

for (i=100000000; i >0  ; i--)

g_count++;

因為將乙個數字和0比較和將其與其他數字比較更加有效率優勢,而且這裡i在迴圈體裡面

並不使用,所以vc編譯器將其變換成上面的形式,可以大大節省迴圈執行的時鐘週期。

這樣,未優化的版本有很大的機會出現 g_count == 五億 就有了解釋,是因為:

cpu對於純粹的整數運算是很快的,一億次迴圈裡面,可能只有一兩次的執行緒上下文切換

沒有優化的版本迴圈體比++操作本身更加耗時,這樣切換操作很可能出現在 for 迴圈中,

而不是 g_count++ 的三條指令之間  

這裡也證明了vc6編譯器對於 ++ 的執行**是是非原子的,查了一下資料 這3條指令在

pentium以後的cpu比一條inc更快

然後再檢查沒有加volatile的優化版本

發現彙編**的迴圈體完全沒有了:

mov    eax, dword ptr _g_count

push    esi

add    eax, 100000000                ; 05f5e100h

表示成c的**大概就是這樣:    g_count+=100000000; 編譯器還是很聰明,發現這個循

環其實使用前面的語句也可以達到目的,乾脆把迴圈拿掉了,這樣因為執行緒執行時間很短

,往往乙個執行緒都執行完了其他執行緒還沒有被排程,所以結果都是5億了。

附帶以下總結:

1. 不要小看編譯器的聰明程度,上面的那些優化,我在gcc上也作了驗證,我們不要太在

意i++/++i之類的優化,要相信編譯器能做好它

2. ++的操作在單cpu的x86上也不是原子性的,所以優化多執行緒效能的兄弟不要在這裡搞過

火,老實用 interlockedincrement 吧

3. x86上,不管是否smp, 對於int(要求位址4 bytes對齊)的讀取和賦值還是原子的,不過

這個就和這個試驗無關了(risc的機器就不要這樣做了,大家還是加鎖吧)

volatile和原子操作

所謂原子操作,就是 不可中斷的乙個或一系列操作 在確認乙個操作是原子的情況下,多執行緒環境裡面,我們可以避免僅僅為保護這個操作在外圍加上效能昂貴的鎖,甚至借助於原子操作,我們可以實現互斥鎖。很多作業系統都為int型別提供了 賦值的原子操作版本,比如 nt 提供了 interlockedexchang...

原子性和volatile

所謂原子操作,就是 不可中斷的乙個或一系列操作 在確認乙個操作是原子的情況下,多執行緒環境裡面,我們可以避免僅僅為保護這個操作在外圍加上效能昂貴的鎖,甚至借助於原子操作,我們可以實現互斥鎖。很多作業系統都為int型別提供了 賦值的原子操作版本,比如 nt 提供了 interlockedexchang...

Volatile關鍵字與原子性操作

原子性操作具有不可分割性。比如 i 0 這個操作是不可分割的,那麼我們說這個操作時原子操作。再比如 i 這個操作實際是 i i 1 那麼x y 這個操作是不是原子性操作呢?答案也是否定的,該操作可以向下細分為首先讀取y的資料,再賦值給x的過程。注意 在32位平台下,對64位資料的讀取和賦值是需要通過...