免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
對 Windows 窗體控件進(jìn)行線程安全調(diào)用 - 夜淡茶清.shenfx - 博客園

對 Windows 窗體控件進(jìn)行線程安全調(diào)用

今天在編寫一個(gè)windows應(yīng)用程序的時(shí)候碰到了一個(gè)小問題,程序需求是這樣的,創(chuàng)建多個(gè)線程調(diào)用執(zhí)行某個(gè)方法,WindowsForm中有個(gè)Progress Bar控件用于顯示已經(jīng)執(zhí)行完畢的進(jìn)程數(shù),即當(dāng)所有的線程都運(yùn)行完畢后,ProgressBar的進(jìn)度也到頭了。先給出初步的實(shí)現(xiàn)方式:

 

 1         private const int MAXTHREAD = 100//最大線程數(shù)
 2         private int n = 0, count = 0//實(shí)際線程數(shù)、已結(jié)束的線程數(shù)
 3 
 4         private void StartTest()
 5         {
 6             n = int.Parse(txtThreadCount.Text); //線程數(shù)
 7             progressBar1.Maximum = n * 10//設(shè)置ProgressBar的最大值
 8 
 9             Thread thread = null;
10             List<Thread> threads = new List<Thread>(MAXTHREAD);
11             ReadTableTest t = new ReadTableTest(tableName, fileds); 
12             t.ThreadExitEvent += new ThreadExit(OnThreadExit); //線程執(zhí)行完畢后通知主界面
13 
14             try
15             {
16                 //創(chuàng)建線程
17                 for (int i = 0; i < n; i++)
18                 {
19                     thread = new Thread(new ThreadStart(t.Run));
20                     threads.Add(thread);
21                 }
22 
23                 //開始調(diào)用接口
24                 foreach (Thread tt in threads)
25                 {
26                     tt.Start();
27                 }
28             }
29             catch (Exception ex)
30             {
31                 MessageBox.Show(ex.Message);
32             }
33         }
34 
35         //線程執(zhí)行完畢后回調(diào)
36         public void OnThreadExit()
37         {
38             count++;
39             this.progressBar1.Value = count * 10//設(shè)置ProgressBar的進(jìn)度
40 
41             //判斷是否全部進(jìn)程已結(jié)束
42             if (count == n)
43             {
44                 MessageBox.Show("所有線程已執(zhí)行完畢!");
45                 ClearState();
46             }
47         }

當(dāng)調(diào)試執(zhí)行這段程序時(shí)在this.progressBar1.Value = count * 10;處,報(bào)出了InvalidOperationException Cross-thread operation not valid異常,在網(wǎng)上搜索一番后,發(fā)現(xiàn)產(chǎn)生該問題的原因如下。

問題原因

由于 Windows窗體控件本質(zhì)上不是線程安全的。因此如果有兩個(gè)或多個(gè)線程適度操作某一控件的狀態(tài)(setvalue),則可能會(huì)迫使該控件進(jìn)入一種不一致的狀態(tài)。還可能出現(xiàn)其他與線程相關(guān)的bug,包括爭用和死鎖的情況。于是在調(diào)試器中運(yùn)行應(yīng)用程序時(shí),如果創(chuàng)建某控件的線程之外的其他線程試圖調(diào)用該控件,則調(diào)試器會(huì)引發(fā)一個(gè)InvalidOperationException

解決方案

對于該異常的解決方案有兩種,一種是關(guān)閉該異常檢測的方式來避免異常的出現(xiàn),經(jīng)過測試發(fā)現(xiàn)此種方法雖然避免了異常的拋出,但是并不能保證程序運(yùn)行結(jié)果的正確性,對于此例來說,經(jīng)常是全部線程結(jié)束時(shí),進(jìn)度條的顯示還未到頭呢。下面再來看看更加優(yōu)雅的解決方案,即通過保證線程的安全性來避免該異常,先來看看兩種方案的代碼。

方案1 

1         public Form1()
2         {
3             InitializeComponent();
4             Control.CheckForIllegalCrossThreadCalls = false;
5         }

 

說明

關(guān)閉CheckForIllegalCrossThreadCalls,這是Control class上的一個(gè)staticproperty,默認(rèn)值為flase,目的在于開關(guān)是否對Handle的可能存在的不一致存取的監(jiān)測;且該項(xiàng)設(shè)置是具有Applicationscope的。

方案2 

 1 //未給出代碼的部分沒有變化
 2         private delegate void SafeSetProgressBarValue(int v);
 3 
 4         //線程執(zhí)行完畢后回調(diào)
 5         public void OnThreadExit()
 6         {
 7             count++;
 8             OnSafeSetValue(count * 10); //使用線程安全的代碼設(shè)置ProgressBar的進(jìn)度
 9 
10             //判斷是否全部進(jìn)程已結(jié)束
11             if (count == n)
12             {
13                 MessageBox.Show("所有線程已執(zhí)行完畢!");
14                 ClearState();
15             }
16         }
17 
18         /// <summary>
19         /// 線程安全的修改ProgressBarValue方式。
20         /// </summary>
21         /// <param name="va"></param>
22         private void OnSafeSetValue(int va)
23         {
24             
25             if (this.progressBar1.InvokeRequired)
26             {
27                 SafeSetProgressBarValue call = delegate(int v) { this.progressBar1.Value = v; };
28  
29                 this.progressBar1.Invoke(call,va);
30             }
31             else
32                 this.progressBar1.Value = va;
33         }

 說明

Windows窗體中的控件被綁定到特定的線程,不具備線程安全性。因此,如果從另一個(gè)線程調(diào)用控件的方法,那么必須使用控件的一個(gè) Invoke方法來將調(diào)用封送到適當(dāng)?shù)木€程。該屬性可用于確定是否必須調(diào)用 Invoke方法,當(dāng)不知道什么線程擁有控件時(shí)這很有用。控件上有四種方法可以安全地從任何線程進(jìn)行調(diào)用:Invoke、BeginInvoke、EndInvoke和 CreateGraphics。對于所有其他方法調(diào)用,當(dāng)從另一個(gè)線程進(jìn)行調(diào)用時(shí),應(yīng)使用這些 Invoke 方法之一。

Control.InvokeRequired 屬性

獲取一個(gè)值,該值指示調(diào)用方在對控件進(jìn)行方法調(diào)用時(shí)是否必須調(diào)用 Invoke 方法,因?yàn)檎{(diào)用方位于創(chuàng)建控件所在的線程以外的線程中。

屬性值

如果控件的 Handle 是在與調(diào)用線程不同的線程上創(chuàng)建的(說明您必須通過 Invoke 方法對控件進(jìn)行調(diào)用),則為 true;否則為 false。

更多資料:

http://msdn2.microsoft.com/zh-cn/library/ms171728(VS.80).aspx

http://msdn2.microsoft.com/zh-cn/library/system.windows.forms.control.invokerequired(VS.80).aspx

http://blog.csdn.net/joem/archive/2006/12/18/1448198.aspx

posted on 2007-02-08 20:47 shenfx 閱讀(679) 評論(0)  編輯 收藏 引用 網(wǎng)摘 所屬分類: 問題解決

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報(bào)
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
談.Net委托與線程——解決窗體假死 - 橫豎都溢 - 博客園
InvokeRequired 屬性 與Invoke方法(轉(zhuǎn))
.net開發(fā)筆記(十八) winform中的等待框
WPF:如何在工作線程中更新窗體的UI元素(Dispatcher機(jī)制)
多線程編程(4):多線程與UI操作
InvokeRequired and Invoke - jacky的日志 - 網(wǎng)易博客
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服