2013-11-25 39 views
1

我一直在讀的書叫多處理器編程的藝術和跨職能來到如get()方法,getandset(),compareandset(),getandIncrease(),getandIncrease()等函數是如何變成原子的?

在它說,這本書上述所有函數都是原子的,我同意,但是我對自己的一些函數如何變成原子函數有了自己的疑問。

爲什麼與功能得到比較成爲原子? - 因爲它必須等到它達到價值或等待,直到某些條件成爲真實,從而產生障礙,因此是原子性的。

我在想這種方式嗎?有沒有我錯過的東西?

當我做

if (tail_index.get() == (head_index.getAndIncrement()) 

這是原子?

+3

原子的意思是「不可分割的」。你看不到原子操作的一部分,它所做的一切似乎都是一次發生的。在你的情況下,沒有什麼可以確保你的兩個get方法是作爲一個來執行的,所以我不會把它稱爲原子的。 –

回答

1

功能是原子如果它似乎瞬間發生。 [1]

這裏,「似乎」意味着從系統其餘部分的角度來看。例如,考慮一個反轉鏈接列表的同步函數。對於外部觀察者來說,操作顯然不會立即發生:讀取和寫入操作需要很多次才能更新所有列表指針。但是,由於鎖始終保持不變,系統的其他部分在此期間不會讀取列表,因此對他們而言,更新即時顯示。

同樣,CAS(比較和設置)操作並不是實際上在現代計算機上立即發生。一個CPU內核需要時間才能獲得對該值的獨佔寫入訪問權限,然後其他內核需要更多時間才能重新獲得讀取訪問權限以查看新值。在此期間,CPU正在並行執行其他指令。爲了確保即時執行的錯覺得以保留,JVM在CAS操作之前和之後發出CPU指令,以確保在CAS完成之前沒有邏輯上的後續讀取被提取並執行(這將允許您在讀取之前先讀取部分鏈接列表例如,實際上你已經佔用了鎖),並且在CAS完成後(這將允許另一個線程在鏈接列表完全更新之前進行鎖定)之前沒有邏輯上在前的寫入被延遲並執行。

這些CPU訂購指令是AtomicInteger.compareAndSetAtomicInteger.weakCompareAndSet(「可能會虛假地失敗」位很容易用循環糾正)之間的關鍵區別。如果沒有排序保證,弱CAS操作不能用於實現大多數併發算法,並且「僅僅是compareAndSet的一個合適替代方案」。

如果這聽起來很複雜...呃...它是!這是爲什麼you can still get a PhD by designing a concurrent algorithm。爲了顯示併發算法的正確性,你必須考慮其他線程可能會干擾你的事情。如果你認爲它們是對手,試圖打破原子性幻覺,這可能會有所幫助。例如,讓我們考慮您的示例:

if (tail_index.get() == (head_index.getAndIncrement())) 

我認爲這是彈出一個項目關閉與指數計數器循環數組實現的堆棧,並執行「如果」,如果身體的方法的一部分堆棧現在是空的。由於head_index和tail_index是分開訪問的,你的對手可以通過儘可能多的操作來「劃分」它們。 (想象一下,例如,你的線程被get和getAndIncrement之間的操作系統中斷)。因此,他可以很容易地將幾十個物品添加到堆棧,然後刪除除了一個以外的所有物品,將head_index 留在之上tail_index ;即使您要刪除堆棧中的最後一項,您的if塊也不會執行。因此,當你的書說get(),getAndSet()等是原子的時候,它並沒有對這些方法的任何可能的實現做一般的說明。它告訴你,Java標準保證它們是原子的,並且通過仔細使用可用的CPU指令,以一種在普通Java中不可能做到的方式這樣做(​​讓你模擬它,但是更昂貴)。

4

通過添加明確的線程安全性,相對某些實例制定了一種方法atomic。在很多情況下,這是通過將方法標記爲​​來完成的。沒有魔力,如果你看看聲稱方法是原子的線程安全類的源代碼,你會看到鎖定。

WRT給你的第二部分,不,它不是原子的。每個方法調用都是原子的,但是當你把兩個放在一起時,這個組合不是原子的getgetAndIncrement已被明確地原子化。一旦你添加了其他代碼(或者這些調用的組合),除非你這麼做,否則它不是原子的。

+0

謝謝你的答案約翰。我仍然困惑於兩個原子操作何時在一起的組合不是原子的?是因爲每個都是在獨立的線程中以原子方式發生並且鬆散的原子性如同洞?像順序一致性不是成分? – solti

+0

這不是因爲每個線程都在單獨的線程中,即使是單個線程也不是原子的。考慮一下,'get'進入並鎖定。它在退出之前釋放鎖。然後,在調用'getAndIncrement'之前,JVM可以接受額外的集合(檢查||),然後嘗試獲取鎖定。任何時候在嘗試重新獲得鎖之前都會釋放鎖,否則可能會有其他東西進入。 –

+2

順便說一句,AtomicXxxx類沒有使用「同步」或鎖。 –

1

不,函數,使用get()不是原子的。但是,例如,getAndIncrementcompareAndSet本身就是原子。這意味着它保證所有的邏輯都是原子的。對於get()還有另外一個保證:當你將原子值發佈到一個線程中時,它立即變得對另一個線程可見(就像易失性字段一樣)。非易失性和非原子值dont:有些情況下,其值被設置爲非易失性字段對其他線程不可見;這些線程會獲得一箇舊值讀取字段的值。

但是你總是可以使用Atomic*類和其他同步原語來編寫原子函數。