偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

C#線程相關(guān)問(wèn)題總結(jié):基本操作及UI控件交互

開(kāi)發(fā) 后端
C#線程相關(guān)問(wèn)題有很多,有多線程的,有單線程的。本文主要討論C#單線程操作以及與UI控件互交方面的一些注意事項(xiàng)。

C#線程在.NET中是一項(xiàng)十分值得探討的對(duì)象。C#是一門支持多線程的語(yǔ)言,因此線程的使用也是比較常見(jiàn)的。由于線程的知識(shí)在Win32編程的時(shí)候已經(jīng)說(shuō)得過(guò)多,所以在.Net中很少介紹這部分(可能.Net不覺(jué)得這部分是它所特有的)。

那么線程相關(guān)的問(wèn)題大致有如下四類(這篇文章只討論單線程、單線程與UI線程這兩方面的問(wèn)題)。

問(wèn)題一,線程的基本操作,例如:暫停、繼續(xù)、停止等;

問(wèn)題二,如何向線程傳遞參數(shù)或者從中得到其返回值;

問(wèn)題三,如何使線程所占用的CPU不要老是***;

***一個(gè),也是問(wèn)題最多的,就是如何在子線程來(lái)控制UI中的控件,換句話說(shuō),就是在線程中控制窗體某些控件的顯示。

對(duì)于問(wèn)題一,我不建議使用Thread類提供的Suspend、Resume以及Abort這三個(gè)方法,前兩個(gè)有問(wèn)題,好像在VS05已經(jīng)屏蔽這兩個(gè)方法;對(duì)于Abort來(lái)說(shuō),除了資源沒(méi)有得到及時(shí)釋放外,有時(shí)候會(huì)出現(xiàn)異常。如何做呢,通過(guò)設(shè)置開(kāi)關(guān)變量來(lái)完成。

對(duì)于問(wèn)題二,我不建議使用靜態(tài)成員來(lái)完成,僅僅為了線程而破壞類的封裝有些得不償失。那如何做呢,通過(guò)創(chuàng)建單獨(dú)的線程類來(lái)完成。

對(duì)于問(wèn)題三來(lái)說(shuō),造成這個(gè)原因是由于線程中進(jìn)行不間斷的循環(huán)操作,從而使CPU完全被子線程占有。那么處理此類問(wèn)題,其實(shí)很簡(jiǎn)單,在適當(dāng)?shù)奈恢谜{(diào)用Thread.Sleep(20)來(lái)釋放所占有CPU資源,不要小看這20毫秒的睡眠,它的作用可是巨大的,可以使其他線程得到CPU資源,從而使你的CPU使用效率降下來(lái)。

看完前面的三個(gè)問(wèn)題的解釋,對(duì)于如何做似乎沒(méi)有給出一個(gè)明確的答案,為了更好地說(shuō)明如何解決這三個(gè)問(wèn)題,我用一個(gè)比較完整的例子展現(xiàn)給大家,代碼如下。

  1. //--------------------------- Sub-thread class ---------------------------------------  
  2. //------------------------------------------------------------------------------------  
  3. //---File:          clsSubThread  
  4. //---Description:   The sub-thread template class file  
  5. //---Author:        Knight  
  6. //---Date:          Aug.21, 2006  
  7. //------------------------------------------------------------------------------------  
  8. //---------------------------{Sub-thread class}---------------------------------------  
  9. namespace ThreadTemplate  
  10. {  
  11.     using System;  
  12.     using System.Threading;  
  13.     using System.IO;  
  14.     /// < summary>  
  15.     /// Summary description for clsSubThread.  
  16.     /// < /summary>  
  17.     public class clsSubThread:IDisposable  
  18.     {  
  19.         private Thread thdSubThread = null;  
  20.         private Mutex mUnique = new Mutex();  
  21.         private bool blnIsStopped;  
  22.         private bool blnSuspended;  
  23.         private bool blnStarted;  
  24.         private int nStartNum;  
  25.         public bool IsStopped  
  26.         {  
  27.             getreturn blnIsStopped; }  
  28.         }  
  29.         public bool IsSuspended  
  30.         {  
  31.             getreturn blnSuspended; }  
  32.         }  
  33.         public int ReturnValue  
  34.         {  
  35.             getreturn nStartNum;}  
  36.         }  
  37.      
  38.         public clsSubThread( int StartNum )  
  39.         {  
  40.             //  
  41.             // TODO: Add constructor logic here  
  42.             //  
  43.             blnIsStopped = true;  
  44.             blnSuspended = false;  
  45.             blnStarted = false;  
  46.              
  47.             nStartNum = StartNum;  
  48.         }  
  49.         /// < summary>  
  50.         /// Start sub-thread  
  51.         /// < /summary>  
  52.         public void Start()  
  53.         {  
  54.             if( !blnStarted )  
  55.             {  
  56.                 thdSubThread = new Thread( new ThreadStart( SubThread ) );  
  57.                 blnIsStopped = false;  
  58.                 blnStarted = true;  
  59.                 thdSubThread.Start();  
  60.             }  
  61.         }  
  62.         /// < summary>  
  63.         /// Thread entry function  
  64.         /// < /summary>  
  65.         private void SubThread()  
  66.         {  
  67.             do 
  68.             {  
  69.                 // Wait for resume-command if got suspend-command here   
  70.                 mUnique.WaitOne();  
  71.                 mUnique.ReleaseMutex();  
  72.                 nStartNum++;  
  73.              
  74.                 Thread.Sleep(1000); // Release CPU here  
  75.             }while( blnIsStopped == false );  
  76.         }  
  77.         /// < summary>  
  78.         /// Suspend sub-thread  
  79.         /// < /summary>  
  80.         public void Suspend()  
  81.         {  
  82.             if( blnStarted && !blnSuspended )  
  83.             {  
  84.                 blnSuspended = true;  
  85.                 mUnique.WaitOne();  
  86.             }  
  87.         }  
  88.      
  89.         /// < summary>  
  90.         /// Resume sub-thread  
  91.         /// < /summary>  
  92.         public void Resume()  
  93.         {  
  94.             if( blnStarted && blnSuspended )  
  95.             {  
  96.                 blnSuspended = false;  
  97.                 mUnique.ReleaseMutex();  
  98.             }  
  99.         }  
  100.         /// < summary>  
  101.         /// Stop sub-thread  
  102.         /// < /summary>  
  103.         public void Stop()  
  104.         {  
  105.             if( blnStarted )  
  106.             {  
  107.                 if( blnSuspended )  
  108.                     Resume();  
  109.                 blnStarted = false;  
  110.                 blnIsStopped = true;  
  111.                 thdSubThread.Join();  
  112.             }  
  113.         }  
  114.         #region IDisposable Members  
  115.         /// < summary>  
  116.         /// Class resources dispose here  
  117.         /// < /summary>  
  118.         public void Dispose()  
  119.         {  
  120.             // TODO:  Add clsSubThread.Dispose implementation  
  121.             Stop();//Stop thread first  
  122.             GC.SuppressFinalize( this );  
  123.         }  
  124.         #endregion  
  125.     }  
  126. }  
  127.  

那么對(duì)于調(diào)用呢,就非常簡(jiǎn)單了,如下:

  1. // Create new sub-thread object with parameters  
  2. clsSubThread mySubThread = new clsSubThread( 5 );  
  3. mySubThread.Start();//Start thread  
  4.  
  5. Thread.Sleep( 2000 );  
  6. mySubThread.Suspend();//Suspend thread   
  7. Thread.Sleep( 2000 );  
  8. mySubThread.Resume();//Resume thread   
  9. Thread.Sleep( 2000 );  
  10. mySubThread.Stop();//Stop thread   
  11. //Get thread's return value  
  12. Debug.WriteLine( mySubThread.ReturnValue );  
  13. //Release sub-thread object  
  14. mySubThread.Dispose();  

在回過(guò)頭來(lái)看看前面所說(shuō)的三個(gè)問(wèn)題。

C#線程相關(guān)問(wèn)題回顧:?jiǎn)栴}一

對(duì)于問(wèn)題一來(lái)說(shuō),首先需要局部成員的支持,那么

  1. private Mutex mUnique = new Mutex();  
  2. private bool blnIsStopped;  
  3. private bool blnSuspended;  
  4. private bool blnStarted;  

光看成員名稱,估計(jì)大家都已經(jīng)猜出其代表的意思。接下來(lái)需要修改線程入口函數(shù),要是這些開(kāi)關(guān)變量能發(fā)揮作用,那么看看SubThread這個(gè)函數(shù)。

  1. /// < summary>  
  2. /// Thread entry function  
  3. /// < /summary>  
  4. private void SubThread()  
  5. {  
  6.     do 
  7.     {  
  8.         // Wait for resume-command if got suspend-command here    
  9.         mUnique.WaitOne();  
  10.         mUnique.ReleaseMutex();  
  11.         nStartNum++;  
  12.       
  13.         Thread.Sleep(1000);  
  14.     }while( blnIsStopped == false );  
  15. }  

函數(shù)比較簡(jiǎn)單,不到十句,可能對(duì)于“blnIsStopped == false”這個(gè)判斷來(lái)說(shuō),大家還比較好理解,這是一個(gè)普通的判斷,如果當(dāng)前Stop開(kāi)關(guān)打開(kāi)了,就停止循環(huán);否則一直循環(huán)。

大家比較迷惑的可能是如下這兩句:

  1. mUnique.WaitOne();  
  2. mUnique.ReleaseMutex();  

這兩句的目的是為了使線程在Suspend操作的時(shí)候能發(fā)揮效果,為了解釋這兩句,需要結(jié)合Suspend和Resume這兩個(gè)方法,它倆的代碼如下。

  1. /// < summary>  
  2. /// Suspend sub-thread  
  3. /// < /summary>  
  4. public void Suspend()  
  5. {  
  6.     if( blnStarted && !blnSuspended )  
  7.     {  
  8.         blnSuspended = true;  
  9.         mUnique.WaitOne();  
  10.     }  
  11. }  
  12.  
  13. /// < summary>  
  14. /// Resume sub-thread  
  15. /// < /summary>  
  16. public void Resume()  
  17. {  
  18.     if( blnStarted && blnSuspended )  
  19.     {  
  20.         blnSuspended = false;  
  21.         mUnique.ReleaseMutex();  
  22.     }  
  23. }  

為了更好地說(shuō)明,還需要先簡(jiǎn)單說(shuō)說(shuō)Mutex類型。對(duì)于此類型對(duì)象,當(dāng)調(diào)用對(duì)象的WaitOne之后,如果此時(shí)沒(méi)有其他線程對(duì)它使用的時(shí)候,就立刻獲得信號(hào)量,繼續(xù)執(zhí)行代碼;當(dāng)再調(diào)用ReleaseMutex之前,如果再調(diào)用對(duì)象的WaitOne方法,就會(huì)一直等待,直到獲得信號(hào)量的調(diào)用ReleaseMutex來(lái)進(jìn)行釋放。這就好比衛(wèi)生間的使用,如果沒(méi)有人使用則可以直接使用,否則只有等待。

明白了這一點(diǎn)后,再來(lái)解釋這兩句所能出現(xiàn)的現(xiàn)象。

  1. mUnique.WaitOne();  
  2. mUnique.ReleaseMutex();  

當(dāng)在線程函數(shù)中,執(zhí)行到“mUnique.WaitOne();”這一句的時(shí)候,如果此時(shí)外界沒(méi)有發(fā)送Suspend消息,也就是信號(hào)量沒(méi)有被占用,那么這一句可以立刻返回。那么為什么要緊接著釋放呢,因?yàn)椴荒芸傉贾盘?hào)量,立即釋放信號(hào)量是避免在發(fā)送Suspend命令的時(shí)候出現(xiàn)等待;如果此時(shí)外界已經(jīng)發(fā)送了Suspend消息,也就是說(shuō)信號(hào)量已經(jīng)被占用,此時(shí)“mUnique.WaitOne();”不能立刻返回,需要等到信號(hào)量被釋放才能繼續(xù)進(jìn)行,也就是需要調(diào)用Resume的時(shí)候,“mUnique.WaitOne();”才能獲得信號(hào)量進(jìn)行繼續(xù)執(zhí)行。這樣才能達(dá)到真正意義上的Suspend和Resume。

至于線程的Start和Stop來(lái)說(shuō),相對(duì)比較簡(jiǎn)單,這里我就不多說(shuō)了。

C#線程相關(guān)問(wèn)題回顧:?jiǎn)栴}二、三

現(xiàn)在再來(lái)分析一下問(wèn)題二,其實(shí)例子比較明顯,是通過(guò)構(gòu)造函數(shù)和屬性來(lái)完成參數(shù)和返回值,這一點(diǎn)我也不多說(shuō)了。如果線程參數(shù)比較多的話,可以考慮屬性來(lái)完成,類似于返回值。

問(wèn)題三,我就更不用多說(shuō)了。有人說(shuō)了,如果子線程中的循環(huán)不能睡眠怎么辦,因?yàn)樗叩脑?,有時(shí)會(huì)造成數(shù)據(jù)丟失,這方面的可以借鑒前面Suspend的做法,如果更復(fù)雜,則牽扯到多線程的同步問(wèn)題,這部分我會(huì)稍后單獨(dú)寫一篇文章。

前三個(gè)問(wèn)題解決了,該說(shuō)說(shuō)最常見(jiàn)的問(wèn)題,如何在子線程中控制窗體控件。這也是寫線程方面程序經(jīng)常遇到的。

首先說(shuō)說(shuō),為什么不能直接在子線程中操縱UI呢。原因在于子線程和UI線程屬于不同的上下文,換句比較通俗的話說(shuō),就好比兩個(gè)人在不同的房間里一樣,那么要你直接操作另一個(gè)房間里的東西,恐怕不行罷,那么對(duì)于子線程來(lái)說(shuō)也一樣,不能直接操作UI線程中的對(duì)象。

那么如何在子線程中操縱UI線程中的對(duì)象呢,.Net提供了Invoke和BeginInvoke這兩種方法。簡(jiǎn)單地說(shuō),就是子線程發(fā)消息讓UI線程來(lái)完成相應(yīng)的操作。

這兩個(gè)方法有什么區(qū)別,這在我以前的文章已經(jīng)說(shuō)過(guò)了,Invoke需要等到所調(diào)函數(shù)的返回,而BeginInvoke則不需要。

用這兩個(gè)方法需要注意的,有如下三點(diǎn):

***個(gè)是由于Invoke和BeginInvoke屬于Control類型的成員方法,因此調(diào)用的時(shí)候,需要得到Control類型的對(duì)象才能觸發(fā),也就是說(shuō)你要觸發(fā)窗體做什么操作或者窗體上某個(gè)控件做什么操作,需要把窗體對(duì)象或者控件對(duì)象傳遞到線程中。

第二個(gè),對(duì)于Invoke和BeginInvoke接受的參數(shù)屬于一個(gè)delegate類型,我在以前的文章中使用的是MethodInvoker,這是.Net自帶的一個(gè)delegate類型,而并不意味著在使用Invoke或者BeginInvoke的時(shí)候只能用它。參看我給的第二篇文章(《如何彈出一個(gè)模式窗口來(lái)顯示進(jìn)度條》),會(huì)有很多不同的delegate定義。

***一個(gè),使用Invoke和BeginInvoke有個(gè)需要注意的,就是當(dāng)子線程在Form_Load開(kāi)啟的時(shí)候,會(huì)遇到異常,這是因?yàn)橛|發(fā)Invoke的對(duì)象還沒(méi)有完全初始化完畢。處理此類問(wèn)題,在開(kāi)啟線程之前顯式的調(diào)用“this.Show();”,來(lái)使窗體顯示在線程開(kāi)啟之前。如果此時(shí)只是開(kāi)啟線程來(lái)初始化顯示數(shù)據(jù),那我建議你不要使用子線程,用Splash窗體的效果可能更好。這方面可以參看如下的例子。

http://www.syncfusion.com/FAQ/WindowsForms/FAQ_c95c.aspx#q621q

線程的四個(gè)相關(guān)問(wèn)題已經(jīng)說(shuō)完了,這篇文章只說(shuō)了單線程,以及單線程與UI線程交互的問(wèn)題。其中涉及到的方法不一定是唯一的,因?yàn)?Net還提供了其他類來(lái)扶助線程操作,這里就不一一羅列。

【編輯推薦】

  1. 學(xué)習(xí)C#多線程:lock的用法
  2. 總結(jié)C#多線程的點(diǎn)點(diǎn)滴滴
  3. 學(xué)習(xí)C#實(shí)現(xiàn)HTTP協(xié)議:多線程文件傳輸
  4. C#子線程操作的一個(gè)小問(wèn)題
  5. C#線程的啟動(dòng)
責(zé)任編輯:yangsai 來(lái)源: 愚翁專欄
相關(guān)推薦

2009-08-27 13:55:08

C#子線程

2010-03-16 19:29:26

Java多線程操作

2009-08-11 15:44:05

C#基本技巧

2009-09-01 17:15:42

C#多線程應(yīng)用

2009-08-05 18:39:54

C#異常類

2009-08-07 13:30:20

C# Excel導(dǎo)入

2009-09-08 17:37:54

C# listbox控

2009-09-16 10:56:22

C#開(kāi)發(fā)ActiveX

2011-04-25 15:15:00

C#

2010-07-23 09:03:53

.NET跨線程

2009-09-01 15:08:07

C#命名規(guī)范

2009-07-17 10:37:05

C#多線程

2024-05-16 12:51:15

WinForms線程UI

2009-08-06 16:05:09

GridView控件

2009-08-18 14:36:36

C# 操作Excel

2009-08-25 15:23:16

C#子線程

2009-08-07 14:00:06

C#路徑

2009-09-08 16:10:03

C# ListBox

2011-05-20 16:07:29

C#

2009-12-24 09:16:11

C#泛型
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)