青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

elva

多線程程序中操作的原子性

轉(zhuǎn)自:
http://www.parallellabs.com/2010/04/15/atomic-operation-in-multithreaded-application/

0. 背景

原子操作就是不可再分的操作。在多線程程序中原子操作是一個非常重要的概念,它常常用來實現(xiàn)一些同步機制,同時也是一些常見的多線程Bug的源頭。本文主要討論了三個問題:1. 多線程程序中對變量的讀寫操作是否是原子的?2. 多線程程序中對Bit field(位域)的讀寫操作是否是線程安全的?3. 程序員該如何使用原子操作?

1. 多線程環(huán)境下對變量的讀寫操作是否是原子的?

我們先從一道很熱門的百度筆試題講起。很多人講不清楚其背后的原理,下面我們就來對它進行一下剖析(其實這個題目有點歧義,后面我們會講到):

以下多線程對int型變量x的操作,哪幾個需要進行同步:( )
A. x=y; B. x++; C. ++x; D. x=1;

要徹底理解這個問題,我們首先需要從硬件講起。以常見的X86 CPU來說,根據(jù)Intel的參考手冊,它基于以下三種機制保證了多核中加鎖的原子操作(8.1節(jié)):
(1)Guaranteed atomic operations (注:8.1.1節(jié)有詳細介紹)
(2)Bus locking, using the LOCK# signal and the LOCK instruction prefix
(3)Cache coherency protocols that ensure that atomic operations can be carried out on cached data structures (cache lock); this mechanism is present in the Pentium 4, Intel Xeon, and P6 family processors

這三個機制相互獨立,相輔相承。簡單的理解起來就是
(1)一些基本的內(nèi)存讀寫操作是本身已經(jīng)被硬件提供了原子性保證(例如讀寫單個字節(jié)的操作);
(2)一些需要保證原子性但是沒有被第(1)條機制提供支持的操作(例如read-modify-write)可以通過使用”LOCK#”來鎖定總線,從而保證操作的原子性
(3)因為很多內(nèi)存數(shù)據(jù)是已經(jīng)存放在L1/L2 cache中了,對這些數(shù)據(jù)的原子操作只需要與本地的cache打交道,而不需要與總線打交道,所以CPU就提供了cache coherency機制來保證其它的那些也cache了這些數(shù)據(jù)的processor能讀到最新的值(關(guān)于cache coherency可以參加我的一篇博文)。

那么CPU對哪些(1)中的基本的操作提供了原子性支持呢?根據(jù)Intel手冊8.1.1節(jié)的介紹:

從Intel486 processor開始,以下的基本內(nèi)存操作是原子的:
• Reading or writing a byte(一個字節(jié)的讀寫)
• Reading or writing a word aligned on a 16-bit boundary(對齊到16位邊界的字的讀寫)
• Reading or writing a doubleword aligned on a 32-bit boundary(對齊到32位邊界的雙字的讀寫)

從Pentium processor開始,除了之前支持的原子操作外又新增了以下原子操作:
• Reading or writing a quadword aligned on a 64-bit boundary(對齊到64位邊界的四字的讀寫)
• 16-bit accesses to uncached memory locations that fit within a 32-bit data bus(未緩存且在32位數(shù)據(jù)總線范圍之內(nèi)的內(nèi)存地址的訪問)

從P6 family processors開始,除了之前支持的原子操作又新增了以下原子操作:
• Unaligned 16-, 32-, and 64-bit accesses to cached memory that fit within a cache line(對單個cache line中緩存地址的未對齊的16/32/64位訪問)

那么哪些操作是非原子的呢?
Accesses to cacheable memory that are split across bus widths, cache lines, and
page boundaries are not guaranteed to be atomic by the Intel Core 2 Duo, Intel®
Atom™, Intel Core Duo, Pentium M, Pentium 4, Intel Xeon, P6 family, Pentium, and
Intel486 processors.(說點簡單點,那些被總線帶寬、cache line以及page大小給分隔開了的內(nèi)存地址的訪問不是原子的,你如果想保證這些操作是原子的,你就得求助于機制(2),對總線發(fā)出相應的控制信號才行)。

需要注意的是盡管從P6 family開始對一些非對齊的讀寫操作已經(jīng)提供了原子性保障,但是非對齊訪問是非常影響性能的,需要盡量避免。當然了,對于一般的程序員來說不需要太擔心這個,因為大部分編譯器會自動幫你完成內(nèi)存對齊。

回到最開始那個筆試題。我們先反匯編一下看看它們到底執(zhí)行了什么操作:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
x = y;
mov eax,dword ptr [y]
mov dword ptr [x],eax
  
x++;
mov eax,dword ptr [x]
add eax,1
mov dword ptr [x],eax
  
++x;
mov eax,dword ptr [x]
add eax,1
mov dword ptr [x],eax
  
x = 1;
mov dword ptr [x],1

(1)很顯然,x=1是原子操作。
因為x是int類型,32位CPU上int占32位,在X86上由硬件直接提供了原子性支持。實際上不管有多少個線程同時執(zhí)行類似x=1這樣的賦值語句,x的值最終還是被賦的值(而不會出現(xiàn)例如某個線程只更新了x的低16位然后被阻塞,另一個線程緊接著又更新了x的低24位然后又被阻塞,從而出現(xiàn)x的值被損壞了的情況)。

(2)再來看x++和++x。
其實類似x++, x+=2, ++x這樣的操作在多線程環(huán)境下是需要同步的。因為X86會按三條指令的形式來處理這種語句:從內(nèi)存中讀x的值到寄存器中,對寄存器加1,再把新值寫回x所處的內(nèi)存地址(見上面的反匯編代碼)。

例如有兩個線程,它們按照如下順序執(zhí)行(注意讀x和寫回x是原子操作,兩個線程不能同時執(zhí)行):

time    Thread 1         Thread 2
0      load eax, x
1                            load eax, x
2      add eax, 1        add eax, 1
3      store x, eax
4                            store x, eax

我們會發(fā)現(xiàn)最終x的值會是1而不是2,因為Thread 1的結(jié)果被覆蓋掉了。這種情況下我們就需要對x++這樣的操作加鎖(例如Pthread中的mutex)以保證同步,或者使用一些提供了atomic operations的庫(例如Windows API中的atomic庫,Linux內(nèi)核中的atomic.h,Java concurrent庫中的Atomic Integer,C++0x中即將支持的atomic_int等等,這些庫會利用CPU提供的硬件機制做一層封裝,提供一些保證了原子性的API)。

(3)最后來看看x=y。
在X86上它包含兩個操作:讀取y至寄存器,再把該值寫入x。讀y的值這個操作本身是原子的,把值寫入x也是原子的,但是兩者合起來是不是原子操作呢?我個人認為x=y不是原子操作,因為它不是不可再分的操作。但是它需要不需要同步呢?其實問題的關(guān)鍵在于程序的上下文。

例如有兩個線程,線程1要執(zhí)行{y = 1; x = y;},線程2要執(zhí)行{y = 2; y = 3;},假設(shè)它們按如下時間順序執(zhí)行:

time    Thread 1        Thread 2
0        store y, 1
1                            store y, 2
2        load eax, y
3                            store y, 3
4        store x, eax

那么最終線程1中x的值為2,而不是它原本想要的1。我們需要加上相應的同步語句確保y = 2不會在線程1的兩條語句之間發(fā)生。y = 3那條語句盡管在load y和store x之間執(zhí)行,但是卻不影響x=y這條語句本身的語義。所以你可以說x=y需要同步,也可以說x=y不需要同步,看你怎么理解題意了。x=1是否需要同步也是一樣的道理,雖然它本身是原子操作,但是如果有另一個線程要讀x=1之后的值,那肯定也需要同步,否則另一個線程讀到的就是x的舊值而不是1了。

2. 對Bit field(位域)的讀寫操作是否是線程安全的?

Bit field常用來高效的存儲有限位數(shù)的變量,多用于內(nèi)核/底層開發(fā)中。一般來說,對同一個結(jié)構(gòu)體內(nèi)的不同bit成員的多線程訪問是無法保證線程安全的。

例如Wikipedia中的如下例子:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
struct foo {
    int flag : 1;
    int counter : 15;
};
  
struct foo my_foo;
  
/* ... */
  
/* in thread 1 */
  
pthread_mutex_lock(&my_mutex_for_flag);
my_foo.flag = !my_foo.flag;
pthread_mutex_unlock(&my_mutex_for_flag);
  
/* in thread 2 */
  
pthread_mutex_lock(&my_mutex_for_counter);
++my_foo.counter;
pthread_mutex_unlock(&my_mutex_for_counter);

兩個線程分別對my_foo.flag和my_foo.counter進行讀寫操作,但是即使有上面的加鎖方式仍然不能保證它是線程安全的。原因在于不同的成員在內(nèi)存中的具體排列方式“跟Byte Order、Bit Order、對齊等問題都有關(guān),不同的平臺和編譯器可能會排列得很不一樣,要編寫可移植的代碼就不能假定Bit-field是按某一種固定方式排列的”[3]。而且一般來講CPU對內(nèi)存操作的最小單位是word(X86的word是16bits),而不是1bit。這就是說,如果my_foo.flag和my_foo.counter存儲在同一個word里,CPU在讀寫任何一個bit member的時候會同時把兩個值一起讀進寄存器,從而造成讀寫沖突。這個例子正確的處理方式是用一個mutex同時保護my_foo.flag和my_foo.counter,這樣才能確保讀寫是線程安全的。

C++0x草案中對bit field是這樣定義的:
連續(xù)的多個非0bit的bit fields是屬于同一個memory location的;長度為0bit的bit field會把占單獨的一個memory location。對同一個memory location的讀寫不是線程安全的;對不同memory location的讀寫是線程安全的。
例如在下圖的例子中bf1和bf2是同一個memory location,bf3是一個單獨的memory location,bf4是一個單獨的memory location:
bit field

這里有一個因為Bit field不是線程安全所導致的一個Linux內(nèi)核中的Bug

引用一下Pongba的總結(jié)

所以,如果你的多個bitfields是連續(xù)的,同時又想要無沖突的讀取它們,有兩種做法,一是在中間用0大小bitfield隔開,但這種做法實際上就消除了bitfield的節(jié)省內(nèi)存的初衷,因為為了使它們不沖突,至少被隔開的兩個bitfield肯定不可能共享byte了。另一種做法當然就是用鎖了。

3. 程序員該怎么用Atomic操作?

一般情況下程序員不需要跟CPU提供的原子操作直接打交道,所以只需要選擇語言或者平臺提供的atomic API即可。而且使用封裝好了的API還有一個好處是它們常常還提供了諸如compare_and_swap,fetch_and_add這樣既有讀又有寫的較復雜操作的封裝。

常見的API如下:

Windows上InterlockedXXXX的API
GNU/Linux上linux kernel中atomic_32.h
GCC中的Atomic Builtins (__sync_fetch_and_add()等)
Java中的java.util.concurrent.atomic
C++0x中的atomic operation
Intel TBB中的atomic operation

4. 參考文獻:

[1] 關(guān)于變量操作的原子性(atomicity)FAQ
[2] http://en.wikipedia.org/wiki/Atomic_operation
[3] 關(guān)于內(nèi)存對齊、bit field等 –《Linux C編程一站式學習》
[4] Do you need mutex to protect an ‘int’?
[5] C++ Concurrency in Action
[6] Multithreaded simple data type access and atomic variables
[6] http://www.newsmth.net/bbscon.php?bid=335&id=236629
[7]
http://www.newsmth.net/bbscon.php?bid=335&id=209239
[8]
http://www.newsmth.net/bbscon.php?bid=335&id=186723
轉(zhuǎn)載請注明來自parallellabs.com

posted on 2011-01-21 13:47 葉子 閱讀(5850) 評論(0)  編輯 收藏 引用 所屬分類: C\C++

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            中文久久精品| 久久久国产精彩视频美女艺术照福利| 久久久人成影片一区二区三区| 亚洲一区国产视频| 国产精自产拍久久久久久蜜| 亚洲第一主播视频| 日韩视频在线一区二区| 亚洲综合色激情五月| 国产日韩欧美亚洲一区| 久久精品在线| 欧美成人首页| 亚洲综合欧美日韩| 欧美一区成人| 亚洲国产一区二区三区高清| 亚洲美女在线观看| 国内精品久久久久久久影视麻豆 | 国产毛片久久| 久久综合伊人77777蜜臀| 欧美高清视频免费观看| 亚洲欧美另类在线观看| 久久久久久久网站| 夜夜嗨av一区二区三区免费区| 亚洲影院色无极综合| 亚洲丶国产丶欧美一区二区三区| 亚洲毛片一区| 精品51国产黑色丝袜高跟鞋| 日韩视频中文| 影音先锋中文字幕一区| 亚洲视频久久| 亚洲黄色成人| 亚洲欧美日韩直播| 日韩视频一区二区三区在线播放| 亚洲欧美国产制服动漫| 亚洲精品女人| 久久久无码精品亚洲日韩按摩| 亚洲午夜女主播在线直播| 久久久国产成人精品| 亚洲欧美综合另类中字| 欧美顶级少妇做爰| 久久夜色精品国产噜噜av| 欧美日韩一区二区三区四区五区| 欧美va天堂va视频va在线| 国产精品毛片| 夜夜狂射影院欧美极品| 亚洲精品护士| 久久这里只有| 美女黄毛**国产精品啪啪| 国产精品日韩欧美一区二区| 亚洲精品在线观看免费| 亚洲欧洲另类国产综合| 久久久视频精品| 久久久久成人精品免费播放动漫| 国产精品国产亚洲精品看不卡15| 亚洲精品1区2区| 亚洲国产小视频| 另类欧美日韩国产在线| 免费看成人av| 精品动漫3d一区二区三区免费| 亚洲嫩草精品久久| 先锋影音一区二区三区| 国产精品捆绑调教| 一区二区三区三区在线| 亚洲桃花岛网站| 欧美日韩在线免费观看| 亚洲美女中出| 亚洲你懂的在线视频| 欧美三区在线视频| 一区二区三区欧美日韩| 亚洲欧美日韩久久精品| 国产视频亚洲| 午夜精品久久久久久久99热浪潮 | 欧美在线啊v一区| 久久久99国产精品免费| 狠狠狠色丁香婷婷综合久久五月| 欧美中文在线观看国产| 另类国产ts人妖高潮视频| 激情成人在线视频| 免费亚洲婷婷| 日韩亚洲视频在线| 欧美在线日韩精品| 国产一区二区三区免费在线观看| 久久久久久久久久看片| 亚洲国产成人久久综合一区| 99在线|亚洲一区二区| 国产精品久久91| 欧美综合激情网| 欧美激情精品久久久久久黑人| 一本色道久久综合亚洲精品不卡 | 狠狠v欧美v日韩v亚洲ⅴ| 久久综合国产精品台湾中文娱乐网| 噜噜爱69成人精品| 一区二区三区久久久| 国产欧美精品| 免费在线欧美黄色| 在线视频精品一| 久久亚洲影音av资源网| 一本久久精品一区二区| 国产日韩欧美a| 欧美精品日韩三级| 西瓜成人精品人成网站| 亚洲电影自拍| 欧美专区中文字幕| 亚洲免费久久| 国产丝袜一区二区| 欧美日韩国产在线播放| 欧美一区2区视频在线观看| 亚洲日本一区二区三区| 久久精品国产精品亚洲精品| 亚洲精品久久久久久久久久久久久| 国产精品国产三级国产专区53 | 性欧美大战久久久久久久久| 亚洲日本中文字幕免费在线不卡| 久久精品视频网| 一区二区三区不卡视频在线观看 | 欧美日韩精品欧美日韩精品| 欧美在线视频一区二区| 99精品视频免费| 欧美.日韩.国产.一区.二区| 午夜精品在线视频| 日韩亚洲欧美一区二区三区| 极品尤物av久久免费看| 国产精品裸体一区二区三区| 欧美精品网站| 久久婷婷久久一区二区三区| 午夜精品视频在线观看一区二区| 亚洲区一区二| 亚洲国产精品视频| 免费不卡亚洲欧美| 久久久久国产精品www| 亚洲欧美www| 亚洲一区二区不卡免费| 亚洲伦理在线| 欧美有码在线视频| 香蕉成人久久| 亚洲一级免费视频| 国产亚洲一区精品| 国产精品老牛| 国产精品v欧美精品v日本精品动漫 | 一区二区三区久久网| 亚洲精品综合| 亚洲精品在线看| 亚洲精品久久久久久久久久久久| 亚洲国产二区| 91久久夜色精品国产九色| 亚洲激情啪啪| 亚洲免费av观看| 在线视频亚洲欧美| 亚洲视频福利| 亚洲一区国产精品| 午夜精品一区二区三区四区| 校园春色国产精品| 久久久久国产成人精品亚洲午夜| 久久精品国产69国产精品亚洲 | 亚洲精品欧洲| 亚洲素人一区二区| 欧美一区二区黄| 欧美中文字幕在线观看| 久久一日本道色综合久久| 玖玖精品视频| 欧美日韩国产三级| 国产精品综合色区在线观看| 韩国女主播一区| 亚洲人成在线影院| 亚洲欧美国产高清| 久久久久一区二区三区四区| 欧美高清在线播放| 99视频一区| 久久精品30| 欧美激情综合五月色丁香小说| 欧美日韩在线高清| 国产一区日韩欧美| 99在线|亚洲一区二区| 欧美一区二区视频免费观看| 麻豆免费精品视频| 日韩视频在线播放| 久久久99精品免费观看不卡| 欧美精品一级| 国产综合视频| 一本色道久久综合亚洲精品小说| 欧美一二三区在线观看| 欧美不卡在线视频| 亚洲视频欧洲视频| 久久综合伊人77777麻豆| 国产精品区免费视频| 亚洲国产精品v| 午夜精品国产精品大乳美女| 欧美成人亚洲成人| 午夜一区在线| 欧美视频在线观看一区| 1204国产成人精品视频| 校园春色综合网| 91久久精品日日躁夜夜躁国产| 亚洲男女毛片无遮挡| 欧美理论电影在线播放| 韩国v欧美v日本v亚洲v| 亚洲欧美日韩国产综合在线| 亚洲国产另类久久久精品极度| 欧美一区=区| 国产精品天天看| 亚洲桃色在线一区|