我看到有很多關於線程修改窗體項目的問題;然而,我只想從線程讀取複選框(例如)的狀態。所以...關於線程窗體訪問開銷的問題
是否有任何額外的開銷來訪問窗體中的複選框的「檢查」狀態(從一個線程)-vs-創建一個布爾將反映該複選框的狀態,並有線程訪問布爾值呢?
我看到有很多關於線程修改窗體項目的問題;然而,我只想從線程讀取複選框(例如)的狀態。所以...關於線程窗體訪問開銷的問題
是否有任何額外的開銷來訪問窗體中的複選框的「檢查」狀態(從一個線程)-vs-創建一個布爾將反映該複選框的狀態,並有線程訪問布爾值呢?
答案是最肯定是有的。原因是因爲正確訪問UI控件狀態涉及很多工作。您基本上必須將方法調用編組到UI線程才能正確訪問控件。編組操作需要通過包含委託引用的消息泵向UI線程發送消息。 UI線程最終會將其提取並執行。由於我從來沒有計時這一行動,我無法肯定地說這是多麼昂貴,但我懷疑這是一筆不小的時間。它必須這樣做,因爲UI控件具有線程關聯性。這意味着它們只能在創建它們的線程上訪問。要委派一名代表,請使用Control.Invoke
或Control.BeginInvoke
方法。
Fredrik已經提到了避免編組操作的一個非常好的解決方法。這是它在代碼中的樣子。
public partial class YourForm : Form
{
// Make sure to mark this variable as volatile.
private volatile bool m_Checked;
private void YourForm_Load(object sender, EventArgs e)
{
m_Checked = YourCheckbox.Checked;
var thread = new Thread(
() =>
{
while (true)
{
// This read will come from main memory since the
// variable is marked as volatile.
bool value = m_Checked;
}
});
thread.Start();
}
private void YourCheckbox_CheckedChanged(object sender, EventArgs e)
{
// This write will be committed to main memory since the
// variable is marked as volatile.
m_Checked = YourCheckbox.Checked;
}
}
無論線程問題如何,我都建議將值存儲在bool
字段中; CheckBox
應該是數據的可視表示,而不是數據本身。這將導致耦合代碼更少,而您決定更改UI的影響更小。
@Ed,我也會非常小心地允許CheckBox在線程運行時主動監視它並更改bool字段的狀態。例如,如果您在監聽線程中監視真/假更改,那麼字段的狀態很可能會從第一個線程快速更改,而不會有監聽線程觀察到更改。 – 2010-08-19 15:05:12
@丹·布萊恩特:但是接下來的問題是線程是否對狀態感興趣(在這種情況下,當閱讀時狀態良好,即使它錯過了一個改變)或者轉換中(在這種情況下,可以認爲一個XXXResetEvent是更合適的觀察對象) – 2010-08-19 16:22:23
線程無法訪問任何表單UI元素,包括讀取複選框的任何屬性。該Control
方法和屬性只能從主UI線程調用:
使用
InvokeRequired
屬性來同步訪問從多個線程 控制。有關多線程 Windows窗體控件 的更多信息,請參閱How to: Make Thread-Safe Calls to Windows Forms Controls
好吧,我認爲這回答了我的問題,但我想確保我清楚...所以你說這樣的邏輯在線程內... if (checkbox_YADA.Checked) ... else ... 實際上下文切換到UI線程,檢索'Checked'bool的值,然後將該信息返回給調用線程?哎呀!如果情況確實如此,那麼通過線程訪問(甚至只讀)表單上的任何內容都是無效的。 請確認... 謝謝。 – 2010-08-19 18:12:07
@Ed:不,切換到UI線程不是自動的。它必須通過'Control.Invoke'手動完成。剛剛描述的邏輯將繼續在工作線程中運行,事實上,大部分時間可能正常工作,特別是因爲CheckBox.Checked屬性只是讀取實例變量。但是,仍然會有內存障礙問題,如果該屬性更復雜,並且需要閱讀窗口句柄或其他東西,那麼所有地獄都可能崩潰,並且您的應用程序將無法預料地和驚人地失敗。 – 2010-08-19 18:29:51