上篇部落格:http://blog.csdn.net/pennyliang/archive/2010/10/20/5953939.aspx提出了一段代碼,並沒有給出解釋,本文接上文繼續展開討論。
該文有很多網友回複,比較集中的看法是CPU位元組對齊,巧合的是有一個朋友用這個代碼做了測試,發現對齊和不對齊的代碼執行的速度是一樣的,原因是他的筆記本安裝的linux作業系統,而筆記本是單核的,所以就出現了這個狀況,如果和CPU位元組對齊,在單核的情況下怎麼會速度一樣呢?另外如果是CPU位元組對齊,把線程去掉,替換成兩個函數依次執行,也應該有效率的差異。
這是一種典型的FALSE SHARING問題,在SMP(對稱式多處理)的架構下常見的問題。SMP簡單的說就是多個CPU核,共用一個記憶體和匯流排,L1 cache也叫晶片緩衝,一般是私人的,即每個CPU核帶一個,L2 cache可能是私人的也可能是部分共用的。
為了表明FALSE SHARE帶來的影響,設計了這個簡單的多線程程式,包含兩個線程,他們分別做求和使用不同的變數,但由於cnt_1的地址和cnt_2的地址在同一條cache line中,實測環境中cnt_1的地址為0x600c00,cnt_2的地址為0x600c08,而cache line的大小為64個位元組(cache line大小可以通過getconf LEVEL1_DCACHE_LINESIZE得到,或者命令cat /sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size得到),這樣就會發生FALSE SHARING問題。將兩個變數在64位元組對齊後,cnt_1的地址為0x600c40,cnt_2的地址為0x600c80,恰好錯開在兩條cache line上,原始碼參加上篇部落格。
FALSE SHARING問題在此前的部落格也有詳細討論,可以參見:http://blog.csdn.net/pennyliang/archive/2010/07/27/5766541.aspx
最後,可能有讀者會問,有誰會這麼腦殘寫這樣的代碼,日常編碼怎麼會碰到這樣的問題呢?我給大家說一個具體的情境,假如有一個lock-free的queues,裡麵包含了很多類型的queue,每個queue包含一個head和一個tail,這兩個值分別被消費者和生產者之間競爭,因此如果不考慮false sharing問題,可能會造成低效代碼。這樣一個多線程共用的隊列結構(多生產者,多消費者共用)用以下哪種結構更好呢?我不再公布答案,有興趣的朋友可以去找找這方面的代碼,看看他們是怎麼寫的。
【1】
struct queues{
type head1
type head2
...
type headn
type tail1
type tail2
...
type tailn
}
【2】
struct queue{
type head1
type tail1
type head2
type tail2
...
type headn
type tailn
}
【3】
struct queue{
type head1
type head2
...
type headn
type add_enough_padding;
type tail1
type tail2
...
type tailn
type add_enough_padding;
}
【4】
struct queue{
type head1
type add_enough_padding;
type tail1
type add_enough_padding;
type head2
type add_enough_padding;
type tail2
type add_enough_padding;
...
type headn
type add_enough_padding;
type tailn
type add_enough_padding;
}
在上次的部落格linux編程的108種奇淫巧計-1(FALSE SHARING)我們給出了代碼,但並沒有解釋,本文給出一些詳細解釋。