小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

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

 ShangShujie 2007-08-20

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

今 天在編寫一個(gè)windows應(yīng)用程序的時(shí)候碰到了一個(gè)小問題,程序需求是這樣的,創(chuàng)建多個(gè)線程調(diào)用執(zhí)行某個(gè)方法,Windows Form中有個(gè)Progress Bar控件用于顯示已經(jīng)執(zhí)行完畢的進(jìn)程數(shù),即當(dāng)所有的線程都運(yùn)行完畢后,Progress Bar的進(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)(set value),則可能會(huì)迫使該控件進(jìn)入一種不一致的狀態(tài)。還可能出現(xiàn)其他與線程相關(guān)的 bug,包括爭(zhēng)用和死鎖的情況。于是在調(diào)試器中運(yùn)行應(yīng)用程序時(shí),如果創(chuàng)建某控件的線程之外的其他線程試圖調(diào)用該控件,則調(diào)試器會(huì)引發(fā)一個(gè) InvalidOperationException

解決方案

對(duì)于該異常的解決方案有兩種,一種是關(guān)閉該異常檢測(cè)的方式來避免異常的出現(xiàn),經(jīng)過 測(cè)試發(fā)現(xiàn)此種方法雖然避免了異常的拋出,但是并不能保證程序運(yùn)行結(jié)果的正確性,對(duì)于此例來說,經(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è)static property,默認(rèn)值為flase,目的在于開關(guān)是否對(duì)Handle的可能存在的不一致存取的監(jiān)測(cè);且該項(xiàng)設(shè)置是具有Application scope的。

方案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í)這很有用??丶嫌兴姆N方法可以安全地從任何線程進(jìn)行調(diào)用:Invoke、BeginInvoke、EndInvoke 和 CreateGraphics。對(duì)于所有其他方法調(diào)用,當(dāng)從另一個(gè)線程進(jìn)行調(diào)用時(shí),應(yīng)使用這些 Invoke 方法之一。

Control.InvokeRequired 屬性

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

屬性值

如果控件的 Handle 是在與調(diào)用線程不同的線程上創(chuàng)建的(說明您必須通過 Invoke 方法對(duì)控件進(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) 評(píng)論(0)  編輯 收藏 引用 網(wǎng)摘 所屬分類: 問題解決

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多