2010-04-08 42 views
5

線程讀取由Delphi VCL事件設置的變量是否安全?線程能否安全地讀取由VCL事件設置的變量?

當用戶點擊VCL TCheckbox時,主線程將boolean設置爲複選框的Checked狀態。

CheckboxState := CheckBox1.Checked; 

在任何時候,一個線程讀取該變量

if CheckBoxState then ... 

不要緊,如果線程「錯過」的變化布爾,因爲線程檢查在一個循環的變量它做了其他的事情。所以最終會看到狀態的改變...

這是安全嗎?或者我需要特殊的代碼?圍繞着讀寫變量(分別在線程和主線程中)的關鍵代碼調用是否足夠和必要?

正如我所說的,如果線程得到「錯誤」的值並不重要,但我一直在想,如果一個線程在主線程處於運行狀態時嘗試讀取變量,則可能存在低級別問題寫它的中間,反之亦然。

我的問題類似於這個:Cross thread reading of a variable who's value is not considered important

(也涉及到我剛纔的問題:Using EnterCriticalSection in Thread to update VCL label

+0

請注意,VCL事件並沒有什麼特別的。您的問題同樣適用於從* any *兩個線程中的* any *類型的函數訪問變量。 – 2010-04-08 15:06:13

回答

6

這是安全的,原因有三:

  • 只有一個線程寫入變量。

  • 該變量只有一個字節,所以沒有辦法讀取不一致的值。它將被讀作TrueFalse。 Delphi boolean值不能有對齊問題。

  • Delphi編譯器沒有廣泛檢查變量是否實際寫入,如果不是,則不會「優化」掉任何代碼。總是讀取非局部變量,不需要volatile說明符。

說了這麼多,如果你真的不能確定這一點,你可以使用一個integer值,而不是布爾的,並使用InterlockedExchange()功能寫入變量。這在這裏是過度的,但是這是一個很好的技術,因爲對於單個機器字大小的值,它可以消除對鎖的需要。

你也可以用適當的同步原語替換boolean,就像一個事件,並且有一個線程塊 - 這將幫助你消除線程中的繁忙循環。

1

對於你給的例子,這將是安全的。從技術上講,主要問題是在變量超出機器字大小的情況下,因此可能會出現高位字和長字不同步的情況。儘管對於小數值,這不是問題。

如果您認爲這是一個潛在的問題,例如使用指針,那麼使用的是一個TCriticalSection來控制讀取和寫入項目。這對於所有實際情況都足夠快,並確保您100%安全。

3

在你的情況(檢查屬性)讀操作是原子,所以它是安全的。這與TThread.Terminated屬性相同;正確對齊的字節,單詞和雙字的簡單讀寫操作是原子的。您可以檢查intel documentation瞭解更多信息:

第8章 - 多處理器管理

8.1.1保證原子操作

英特爾486處理器(以及因爲更新的處理器),保證了以下 基本內存操作將始終原子進行:

  • 讀取或寫入字節
  • 讀取或寫入字中的16位邊界
  • 雷丁上對齊或寫入32位邊界

奔騰處理器(和更新的處理器,因爲)上對齊的雙字保證了以下 額外的存儲器操作將總是進行出原子:

  • 讀取或寫入的64位邊界
  • 16位訪問,以適應一個32位數據總線內的非高速緩存存儲器位置上對準的四字