乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      多線程 進(jìn)度條 C# .net

       自由峰 2009-07-27
        多線程 進(jìn)度條 C# .net 收藏
      前言
        在我們應(yīng)用程序開發(fā)過(guò)程中,經(jīng)常會(huì)遇到一些問(wèn)題,需要使用多線程技術(shù)來(lái)加以解決。本文就是通過(guò)幾個(gè)示例程序給大家講解一下多線程相關(guān)的一些主要問(wèn)題。
      執(zhí)行長(zhǎng)任務(wù)操作
        許多種類的應(yīng)用程序都需要長(zhǎng)時(shí)間操作,比如:執(zhí)行一個(gè)打印任務(wù),請(qǐng)求一個(gè) Web Service 調(diào)用等。用戶在這種情況下一般會(huì)去轉(zhuǎn)移做其他事情來(lái)等待任務(wù)的完成,同時(shí)還希望隨時(shí)可以監(jiān)控任務(wù)的執(zhí)行進(jìn)度。

      /P>
       
        下面的代碼片斷示例了當(dāng)長(zhǎng)任務(wù)執(zhí)行時(shí)用戶界面是如何被更新的。

      // 顯示進(jìn)度條
      void ShowProgress( int totalStep, int currentStep )
      {
      _Progress.Maximum = totalStep;
      _Progress.Value = currentStep;
      }
      // 執(zhí)行任務(wù)
      void RunTask( int seconds )
      {
      // 每 1 / 4 秒 顯示進(jìn)度一次
      for( int i = 0; i < seconds * 4; i++ )
      {
      Thread.Sleep( 250 );
      // 顯示進(jìn)度條
      ShowProgress( seconds * 4, i + 1 );
      }
      }
      private void _btnRun_Click( object sender, System.EventArgs e )
      {
      RunTask( Convert.ToInt32( _txtSecond.Value ) );
      }

        當(dāng)我們運(yùn)行上面的程序,在整個(gè)長(zhǎng)任務(wù)的過(guò)程中,沒有出現(xiàn)任何問(wèn)題。這樣就真的沒有問(wèn)題了嗎?當(dāng)我們切換應(yīng)用程序去做其他事情后再切換回來(lái),問(wèn)題就發(fā)生了!主窗體就會(huì)出現(xiàn)如下情況:
       

        這個(gè)問(wèn)題當(dāng)然會(huì)發(fā)生,因?yàn)槲覀儸F(xiàn)在的應(yīng)用程序是單線程的,因此,當(dāng)線程執(zhí)行長(zhǎng)任務(wù)時(shí),它同時(shí)也就不能重畫用戶界面了。
        為什么在我們切換應(yīng)用程序后,問(wèn)題才發(fā)生呢?這是因?yàn)楫?dāng)你切換當(dāng)前應(yīng)用程序到后臺(tái)再切換回前臺(tái)時(shí),我們需要重畫整個(gè)用戶界面。但是應(yīng)用程序正在執(zhí)行長(zhǎng)任務(wù),根本沒有時(shí)間處理用戶界面的重畫,問(wèn)題就會(huì)發(fā)生。
        如何解決問(wèn)題呢?我們需要將長(zhǎng)任務(wù)放在后臺(tái)運(yùn)行,把用戶界面線程解放出來(lái),因此我們需要另外一個(gè)線程。
      線程異步操作
        我們上面程序中執(zhí)行按鈕的Click 處理如下:

      private void _btnRun_Click( object sender, System.EventArgs e )
      {
      RunTask( Convert.ToInt32( _txtSecond.Value ) );
      }

        回想上面剛才問(wèn)題發(fā)生的原因,直到 RunTask 執(zhí)行完成后返回,Click 處理函數(shù)始終不能夠返回,這就意味著用戶界面不能處理重畫事件或其他任何事件。一個(gè)解決方法就是創(chuàng)建另外一個(gè)線程,代碼片斷如下:

      using System.Threading;
      private int _seconds;
      // 執(zhí)行任務(wù)工作線程進(jìn)入點(diǎn)
      void RunTaskThreadStart()
      {
      RunTask( _seconds );
      }
      // 通過(guò)創(chuàng)建工作線程消除用戶界面線程的阻塞問(wèn)題
      private void _btnRun_Click( object sender, System.EventArgs e )
      {
      _seconds = Convert.ToInt32( _txtSecond.Value );
      Thread runTaskThread = new Thread( new ThreadStart( RunTaskThreadStart ) );
      runTaskThread.Start();
      }

        現(xiàn)在,我們不再需要等待 RunTask 執(zhí)行完成才能夠從 Click 事件返回,我們創(chuàng)建了新的工作線程并讓它開始工作、運(yùn)行。
       

        runTaskThread.Start(); 將我們新創(chuàng)建的工作線程調(diào)度執(zhí)行并立即返回,允許我們的用戶界面線程重新獲得控制權(quán)執(zhí)行它自己的工作?,F(xiàn)在如果用戶再切換應(yīng)用程序,因?yàn)楣ぷ骶€程在自己的空間執(zhí)行長(zhǎng)任務(wù),用戶界面線程被解放出來(lái)處理包括用戶界面重畫的各種事件,我們上面遇到的問(wèn)題就解決了。
      委托異步調(diào)用
        在上面的代碼中,我們注意到,我們沒有給工作線程進(jìn)入點(diǎn)(RunTaskThreadStart)傳遞任何參數(shù),我們采用聲明一個(gè)窗體類的字段 _seconds 來(lái)給工作線程傳遞參數(shù)。在某種應(yīng)用場(chǎng)合不能夠給工作線程直接傳遞參數(shù)也是一件非常痛苦的事情。
        如何改進(jìn)呢?我們可以使用委托來(lái)進(jìn)行異步調(diào)用。委托是支持傳遞參數(shù)的。這樣,就消除了我們剛才的問(wèn)題,使我們能夠消除額外的字段聲明和額外的工作線程函數(shù)。
        如果你不熟悉委托,你可以簡(jiǎn)單的把它理解為安全的函數(shù)指針。采用了委托異步調(diào)用,代碼片斷如下:

      // 執(zhí)行任務(wù)的委托聲明
      delegate void RunTaskDelegate( int seconds );
      // 通過(guò)創(chuàng)建委托解決傳遞參數(shù)問(wèn)題
      private void _btnRun_Click( object sender, System.EventArgs e )
      {
      RunTaskDelegate runTask = new RunTaskDelegate( RunTask );
      // 委托同步調(diào)用方式
      runTask( Convert.ToInt16( _txtSecond.Value ) );
      }
      //通過(guò)創(chuàng)建委托解決傳遞參數(shù)問(wèn)題,通過(guò)委托的異步調(diào)用消除用戶界面線程的阻塞問(wèn)題
      private void _btnRun_Click( object sender, System.EventArgs e )
      {
      RunTaskDelegate runTask = new RunTaskDelegate( RunTask );
      // 委托異步調(diào)用方式
      runTask.BeginInvoke( Convert.ToInt16( _txtSecond.Value ), null, null );
      }
      多線程安全
        到這里為止,我們已經(jīng)解決了長(zhǎng)任務(wù)的難題和傳遞參數(shù)的困擾。但是我們真的解決了全部問(wèn)題嗎?回答是否定的。
        我們知道 Windows 編程中有一個(gè)必須遵守的原則,那就是在一個(gè)窗體創(chuàng)建線程之外的任何線程中都不允許操作窗體。
        我們上面的程序就是存在這樣的問(wèn)題:工作線程是在 ShowProgress 方法中修改了用戶界面的進(jìn)度條的屬性。那為什么程序運(yùn)行沒有出現(xiàn)問(wèn)題,運(yùn)行正常呢?
        沒有發(fā)生問(wèn)題是因?yàn)槭乾F(xiàn)在的Windows XP操作系統(tǒng)對(duì)這類問(wèn)題有非常健壯的解決方法,讓我們避免了問(wèn)題的發(fā)生。但是我們現(xiàn)在的程序不能保證在其他的操作系統(tǒng)能夠運(yùn)行正常!
        真正的解決方法是我們能夠認(rèn)識(shí)到問(wèn)題所在,并在程序中加以避免。
       

        如何避免多線程的窗體資源訪問(wèn)的安全問(wèn)題呢?其實(shí)非常簡(jiǎn)單,有兩種方法:
        一種方法就是不管線程是否是用戶界面線程,對(duì)用戶界面資源的訪問(wèn)統(tǒng)一由委托完成;
        另一種方法是在每個(gè) Windows Forms 用戶界面類中都有一個(gè) InvokeRequired 屬性,它用來(lái)標(biāo)識(shí)當(dāng)前線程是否能夠直接訪問(wèn)窗體資源。我們只需要檢查這個(gè)屬性的值,只有當(dāng)允許直接訪問(wèn)窗體資源時(shí)才直接訪問(wèn)相應(yīng)的資源,否則,就需要通過(guò)委托進(jìn)行訪問(wèn)了。
        采用第一種安全的方法的代碼片斷如下:

      // 顯示進(jìn)度條的委托聲明
      delegate void ShowProgressDelegate( int totalStep, int currentStep );
      // 顯示進(jìn)度條
      void ShowProgress( int totalStep, int currentStep )
      {
      _Progress.Maximum = totalStep;
      _Progress.Value = currentStep;
      }
      // 執(zhí)行任務(wù)的委托聲明
      delegate void RunTaskDelegate( int seconds );
      // 執(zhí)行任務(wù)
      void RunTask( int seconds )
      {
      ShowProgressDelegate showProgress = new ShowProgressDelegate( ShowProgress );
      // 每 1 / 4 秒 顯示進(jìn)度一次
      for( int i = 0; i < seconds * 4; i++ )
      {
      Thread.Sleep( 250 );
      // 顯示進(jìn)度條
      this.Invoke( showProgress, new object[] { seconds * 4, i + 1 } );
      }
      }

        采用第二種安全的方法的代碼片斷如下:

      // 顯示進(jìn)度條的委托聲明
      delegate void ShowProgressDelegate( int totalStep, int currentStep );
      // 顯示進(jìn)度條
      void ShowProgress( int totalStep, int currentStep )
      {
      if( _Progress.InvokeRequired )
      {
      ShowProgressDelegate showProgress = new ShowProgressDelegate( ShowProgress );
      // 為了避免工作線程被阻塞,采用異步調(diào)用委托
      this.BeginInvoke( showProgress, new object[] { totalStep, currentStep } );
      }
      else
      {
      _Progress.Maximum = totalStep;
      _Progress.Value = currentStep;
      }
      }
      // 執(zhí)行任務(wù)的委托聲明
      delegate void RunTaskDelegate( int seconds );
      // 執(zhí)行任務(wù)
      void RunTask( int seconds )
      {
      // 每 1 / 4 秒 顯示進(jìn)度一次
      for( int i = 0; i < seconds * 4; i++ )
      {
      Thread.Sleep( 250 );
      // 顯示進(jìn)度條
      ShowProgress( seconds * 4, i + 1 );
      }
      }

        至此,我們用了幾個(gè)示例說(shuō)明了如何執(zhí)行長(zhǎng)任務(wù)、如何通過(guò)多線程異步處理任務(wù)進(jìn)度的顯示并解決了多線程的安全性等問(wèn)題。希望能夠給大家對(duì)理解多線程編程、委托的使用、異步調(diào)用等方面提供一些幫助,也希望能和大家進(jìn)行進(jìn)一步的溝通和交流。

      本文來(lái)自CSDN博客,轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://blog.csdn.net/hanghangaidoudou/archive/2008/03/08/2158045.aspx

        本站是提供個(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)論公約

        類似文章 更多