C# 如何在調用控制項時做到 Thread-safe(線程安全)?
我的一個程序採用回調機制來處理一個任務,這個任務同一時間是只能執行一次的。
開始的時候我會disable所有設置選項,在結束的回調函數里再把它們設置回Enabled。按照MSDN和在百度谷歌上的大部分方法(How to: Make Thread-Safe Calls to Windows Forms Controls),都是聲明一個託管,然後寫一個函數看是否需要Invoke(InvokeRequired)然後處理。我需要操作的空間比較多,這種方法要寫好多代碼,而且還只能訪問操作一個屬性Enabled,如果想干別的比如改變text又要多寫一個託管(或者多加一個參數)。有沒有什麼簡單的方法讓我來訪問UI控制項,哪怕是寫一個託管能訪問那個控制項所有屬性和函數,或者是一個託管能訪問好幾個UI控制項的一個屬性或函數。我試了一個方法可行就是用lock,不會報線程不安全錯誤。不知道這樣是不是可以。lock(control){ control.Enabled = true; control.Text = "xxxx";
}想問問大家還有沒有什麼更好的方法?================================================解決方案:
================================================感謝知友的回答,今天我諮詢了下我們公司的首席架構師,他讓我看了一個東西我想解決了我的問題。這裡面提到的function只需要一個託管我就可以隨意改變Control的任何屬性thread-safely
private delegate void SetControlPropertyThreadSafeDelegate(Control control, string propertyName, object propertyValue);
public static void SetControlPropertyThreadSafe(Control control, string propertyName, object propertyValue)
{
if (control.InvokeRequired)
{
control.Invoke(new SetControlPropertyThreadSafeDelegate(SetControlPropertyThreadSafe), new object[] { control, propertyName, propertyValue });
}
else
{
control.GetType().InvokeMember(propertyName, BindingFlags.SetProperty, null, control, new object[] { propertyValue });
}
}
如果你看明白了這段例子,應該就不難理解了。
這個例子一共提供了三個處理方式,第一個是不安全的,我們就不用看了。
第二個是使用Invoke方法傳一個委託進去,分配到UI線程上執行。一般情況下我們都採用這個方法:
private void SetText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.textBox1.Text = text;
}
}
將委託用Invoke方法調用,可以將委託中的代碼傳送到UI線程上安全的執行。在這個委託裡面,你可以安全的改變任何控制項的狀態和值,如果你要傳遞多個參數,看到那個object[]了沒?
當然,也可以直接用閉包的形式傳進去。
用心看代碼,用心寫代碼。多看多試,這種問題老實說自己試試比來這裡提問快多了。C#不清楚。很多GUI toolkit都有一種功能,讓回調在控制項的那個線程里被執行。
又找到了一個好方法:
this.Invoke(new Action(() =&> { this.Text = "xxx"; }));
這樣設置form元素的東西真是太方便了。。一行代碼就可以,什麼都不用聲明
在控制項上直接用Invoke就會在控制項創建的線程執行,安全……
請注意,在Form_Load階段的控制項invoke存在風險,請先讓其show……血淚坑,我的日誌子系統……推薦閱讀:
※多線程是否有意義?
※boost 是否像 Linux 一樣提供讀寫自旋鎖機制?
※多線程讀內存變慢如何解決?
※為什麼在同一進程中創建不同線程,但線程各自的變數無法在線程間互相訪問?