閱讀Test-and-Set Wikipedia entry之後,我仍然留下了一個問題:「測試和集合將用於什麼?」什麼是測試和設置?
我意識到你可以使用它來實現Mutex(如維基百科中所述),但它有什麼其他用途?
閱讀Test-and-Set Wikipedia entry之後,我仍然留下了一個問題:「測試和集合將用於什麼?」什麼是測試和設置?
我意識到你可以使用它來實現Mutex(如維基百科中所述),但它有什麼其他用途?
您可以在任何時候在任何時候將數據寫入內存後使用它,並確保另一個線程在您啓動後沒有覆蓋目標。很多lock/mutex-free algorithms採取這種形式。
基本上,考慮到原子性的巨大重要性,它的用途正好適用於互斥體。而已。
測試和設置是一個可以用兩個其他指令執行的操作,非原子和更快(原子性在多處理器系統上承受硬件開銷),因此通常不會因其他原因使用它。
一個很好的例子是「增量」。
說兩個線程執行a = a + 1
。假設a
從值100
開始。如果兩個線程同時運行(多核),兩者都將加載a
作爲100
,增加到101
,並將其存儲回a
。錯誤!
隨着測試和設置,你說「設置a
到101
,但只有當它的值爲100
。」在這種情況下,一個線程將通過該測試,但另一個線程將失敗。在失敗的情況下,線程可以重試整個語句,這次加載a
爲101
。成功。
這通常比使用互斥,因爲速度快:
當您需要獲取共享值,對其執行操作並更改該值(假設其他線程尚未更改)時,會使用它。
至於實際應用,我最後一次看到它是在併發隊列的實現中(隊列可能被多線程推送/彈出而不需要信號或互斥)。
爲什麼要使用TestAndSet而不是互斥量?因爲它通常比互斥鎖需要更少的開銷。在互斥體需要OS干預的情況下,TestAndSet可以作爲CPU上的單個原子指令實現。在具有100個線程的並行環境中運行時,代碼關鍵部分中的單個互斥量可能會導致嚴重的瓶頸。
想象一下,您正在撰寫銀行申請,而您的申請有要求從賬戶中提取十英鎊(是的,我是英文的)。因此,您需要將當前帳戶餘額讀入局部變量,減去提款,然後將餘額寫回內存。
但是,如果在讀取值和寫出它之間發生另一個併發請求,該怎麼辦?有可能該請求的結果將被第一個完全覆蓋,並且帳戶餘額將不正確。
測試和設置幫助我們通過檢查您的覆蓋值是您認爲應該是什麼來解決該問題。在這種情況下,您可以檢查餘額是您讀取的原始值。由於它是原子性的,因此它是不可中斷的,因此在閱讀和寫作之間沒有人能夠從你之下拉出地毯。
解決同樣問題的另一種方法是取出內存位置的鎖。不幸的是,鎖定非常難以正確,難以推理,存在可擴展性問題,並且在出現故障時表現不佳,所以它們不是理想的(但絕對實用的)解決方案。測試和設置方法構成了一些軟件事務存儲器的基礎,它們樂觀地允許每個事務同時執行,但是如果它們發生衝突,則將它們全部回滾。
+1你剛剛幫我解決了我正在處理的一個問題。 – 2011-12-01 21:16:26
@ jason-cohen:這實際上是[Compare and Swap](https://en.wikipedia.org/wiki/Compare-and-swap)的描述。測試和設置通常只涉及值0和1. ** set **部分是指將指定內存位置的值設置爲1.它返回前一個值,即1或0,並執行所有操作在一個單一的原子操作。 – 2013-06-29 04:48:25