• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            為生存而奔跑

               :: 首頁(yè) :: 聯(lián)系 :: 聚合  :: 管理
              271 Posts :: 0 Stories :: 58 Comments :: 0 Trackbacks

            留言簿(5)

            我參與的團(tuán)隊(duì)

            搜索

            •  

            積分與排名

            • 積分 - 328985
            • 排名 - 74

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            當(dāng)執(zhí)行的任務(wù)需要很長(zhǎng)時(shí)間時(shí),要用到多線程,在新線程中執(zhí)行任務(wù)。
            有兩種方法:
            一、使用Thread類(lèi)
                Thread workThread=new Thread(new ThreadStart(WorkMethod));
                wordThread.start();
                這樣,就在后臺(tái)執(zhí)行WorkMethod方法了。
            using System;
            using System.Collections.Generic;
            using System.ComponentModel;
            using System.Data;
            using System.Drawing;
            using System.Text;
            using System.Windows.Forms;
            using System.Threading;

            namespace CShapApp
            {
                public partial class Form1 : Form
                {
                    public Form1()
                    {
                        InitializeComponent();
                    }

                    private int seconds;

                    private void btnButton_Click(object sender, EventArgs e)
                    {
                        seconds = Convert.ToInt32(this.textBox1.Text);
                        Thread workThread = new Thread(new ThreadStart(CountingDown));
                        workThread.Start();
                    }

                    private void CountingDown()
                    {
                        this.progressBar1.Maximum = seconds;
                        this.progressBar1.Minimum = 0;
                        this.progressBar1.Value = 0;
                        this.progressBar1.Step = 1;
                        for (int i = 0; i < seconds; i++)
                        {
                            Thread.Sleep(25);
                            this.progressBar1.PerformStep();
                this.progressBar1.Refresh();
                        }
                    }
                }
            }
                但是,由于ThreadStart是委托,不能帶參數(shù)。因此,如果需要參數(shù),可以考慮下面的方法
            二、通過(guò)beginInvoke。
                 由于beginInvoke是異步調(diào)用,因此可以在后臺(tái)運(yùn)行。而begininvoke調(diào)用時(shí)還可以帶參數(shù)。
                 BeginInvoke(Delegate,object[]) ,object[]就是參數(shù)
            using System;
            using System.Collections.Generic;
            using System.ComponentModel;
            using System.Data;
            using System.Drawing;
            using System.Text;
            using System.Windows.Forms;
            using System.Threading;

            namespace CShapApp
            {
                public partial class Form1 : Form
                {
                    public Form1()
                    {
                        InitializeComponent();
                    }

                    private delegate void WorkDelegate(int seconds);
                    private delegate void RefreshProgressBarDelegate();

                    private void btnButton_Click(object sender, EventArgs e)
                    {
                        Thread curThread = Thread.CurrentThread;
                        curThread.Name = "UI thread";

                        int seconds = Convert.ToInt32(this.textBox1.Text);
                        WorkDelegate workDelegate = new WorkDelegate(CountingDown);
                        workDelegate.BeginInvoke(seconds, null, null);
                        //Thread workThread = new Thread(new ThreadStart(CountingDown));
                        //workThread.Start();
                    }

                    private void CountingDown(int seconds)
                    {
                        MessageBox.Show(Thread.CurrentThread.Name);
                        this.progressBar1.Maximum = seconds;
                        this.progressBar1.Minimum = 0;
                        this.progressBar1.Value = 0;
                        this.progressBar1.Step = 1;
                        RefreshProgressBarDelegate refreshProgressBarDelegate = new RefreshProgressBarDelegate(RefreshProgressBar);

                        for (int i = 0; i < seconds; i++)
                        {
                            Thread.Sleep(250);

                            this.progressBar1.Invoke(refreshProgressBarDelegate);
                        }
                    }

                    private void RefreshProgressBar()
                    {
                        this.progressBar1.PerformStep();
                        this.progressBar1.Refresh();
                    }
                }
            }

             

            轉(zhuǎn)自:

            在我們應(yīng)用程序開(kāi)發(fā)過(guò)程中,經(jīng)常會(huì)遇到一些問(wèn)題,需要使用多線程技術(shù)來(lái)加以解決。本文就是通過(guò)幾個(gè)示例程序給大家講解一下多線程相關(guān)的一些主要問(wèn)題。

            執(zhí)行長(zhǎng)任務(wù)操作

              許多種類(lèi)的應(yīng)用程序都需要長(zhǎng)時(shí)間操作,比如:執(zhí)行一個(gè)打印任務(wù),請(qǐng)求一個(gè) Web Service 調(diào)用等。用戶(hù)在這種情況下一般會(huì)去轉(zhuǎn)移做其他事情來(lái)等待任務(wù)的完成,同時(shí)還希望隨時(shí)可以監(jiān)控任務(wù)的執(zhí)行進(jìn)度。

            ?/P>

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

            // 顯示進(jìn)度條
            void ShowProgress( int totalStep, int currentStep )
            {
            _Progress.Maximum 
            = totalStep;
            _Progress.Value 
            = currentStep;
            }


            // 執(zhí)行任務(wù)
            void RunTask( int seconds )
            {
            // 每 1 / 4 秒 顯示進(jìn)度一次
            forint 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ò)程中,沒(méi)有出現(xiàn)任何問(wèn)題。這樣就真的沒(méi)有問(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í)也就不能重畫(huà)用戶(hù)界面了。

            為什么在我們切換應(yīng)用程序后,問(wèn)題才發(fā)生呢?這是因?yàn)楫?dāng)你切換當(dāng)前應(yīng)用程序到后臺(tái)再切換回前臺(tái)時(shí),我們需要重畫(huà)整個(gè)用戶(hù)界面。但是應(yīng)用程序正在執(zhí)行長(zhǎng)任務(wù),根本沒(méi)有時(shí)間處理用戶(hù)界面的重畫(huà),問(wèn)題就會(huì)發(fā)生。

            如何解決問(wèn)題呢?我們需要將長(zhǎng)任務(wù)放在后臺(tái)運(yùn)行,把用戶(hù)界面線程解放出來(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ù)始終不能夠返回,這就意味著用戶(hù)界面不能處理重畫(huà)事件或其他任何事件。一個(gè)解決方法就是創(chuàng)建另外一個(gè)線程,代碼片斷如下:

            using System.Threading;

            private int _seconds;

            // 執(zhí)行任務(wù)工作線程進(jìn)入點(diǎn)
            void RunTaskThreadStart()
            {
            RunTask( _seconds );
            }


            // 通過(guò)創(chuàng)建工作線程消除用戶(hù)界面線程的阻塞問(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)建了新的工作線程并讓它開(kāi)始工作、運(yùn)行。

              runTaskThread.Start(); 將我們新創(chuàng)建的工作線程調(diào)度執(zhí)行并立即返回,允許我們的用戶(hù)界面線程重新獲得控制權(quán)執(zhí)行它自己的工作。現(xiàn)在如果用戶(hù)再切換應(yīng)用程序,因?yàn)楣ぷ骶€程在自己的 空間執(zhí)行長(zhǎng)任務(wù),用戶(hù)界面線程被解放出來(lái)處理包括用戶(hù)界面重畫(huà)的各種事件,我們上面遇到的問(wèn)題就解決了。

            委托異步調(diào)用

              在上面的代碼中,我們注意到,我們沒(méi)有給工作線程進(jìn)入點(diǎn)(RunTaskThreadStart)傳遞任何參數(shù),我們采用聲明一個(gè)窗體類(lèi)的字段 _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)用消除用戶(hù)界面線程的阻塞問(wèn)題
            private void _btnRun_Click( object sender, System.EventArgs e )
            {
            RunTaskDelegate runTask 
            = new RunTaskDelegate( RunTask );

            // 委托異步調(diào)用方式
            runTask.BeginInvoke( Convert.ToInt16( _txtSecond.Value ), nullnull );
            }

             

            多線程安全

              到這里為止,我們已經(jīng)解決了長(zhǎng)任務(wù)的難題和傳遞參數(shù)的困擾。但是我們真的解決了全部問(wèn)題嗎?回答是否定的。

            我們知道 Windows 編程中有一個(gè)必須遵守的原則,那就是在一個(gè)窗體創(chuàng)建線程之外的任何線程中都不允許操作窗體。

            我們上面的程序就是存在這樣的問(wèn)題:工作線程是在 ShowProgress 方法中修改了用戶(hù)界面的進(jìn)度條的屬性。那為什么程序運(yùn)行沒(méi)有出現(xiàn)問(wèn)題,運(yùn)行正常呢?

            沒(méi)有發(fā)生問(wèn)題是因?yàn)槭乾F(xiàn)在的Windows XP操作系統(tǒng)對(duì)這類(lèi)問(wèn)題有非常健壯的解決方法,讓我們避免了問(wèn)題的發(fā)生。但是我們現(xiàn)在的程序不能保證在其他的操作系統(tǒng)能夠運(yùn)行正常!

              真正的解決方法是我們能夠認(rèn)識(shí)到問(wèn)題所在,并在程序中加以避免。

              如何避免多線程的窗體資源訪問(wèn)的安全問(wèn)題呢?其實(shí)非常簡(jiǎn)單,有兩種方法:

            一種方法就是不管線程是否是用戶(hù)界面線程,對(duì)用戶(hù)界面資源的訪問(wèn)統(tǒng)一由委托完成;

            另一種方法是在每個(gè) Windows Forms 用戶(hù)界面類(lèi)中都有一個(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)度一次
            forint 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)度一次
            forint 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)一步的溝通和交流。

             

            posted on 2010-03-31 18:44 baby-fly 閱讀(1144) 評(píng)論(0)  編輯 收藏 引用 所屬分類(lèi): C#
            色妞色综合久久夜夜| 亚洲天堂久久精品| 色综合久久中文字幕无码| 久久超乳爆乳中文字幕| 欧美午夜精品久久久久免费视| 久久99精品久久久久久hb无码| 香港aa三级久久三级| 日本加勒比久久精品| 久久人人爽爽爽人久久久| 26uuu久久五月天| 99久久国产宗和精品1上映| 97精品久久天干天天天按摩| 久久国产免费| 精品久久久久香蕉网| 色综合久久88色综合天天 | 久久99国内精品自在现线| 久久性生大片免费观看性| 97久久香蕉国产线看观看| 香蕉久久影院| 国产精自产拍久久久久久蜜| 久久人人爽人人爽人人片AV不| 人妻无码精品久久亚瑟影视| 97久久精品国产精品青草| 久久精品卫校国产小美女| 久久久精品久久久久特色影视| 97久久国产亚洲精品超碰热| 中文字幕日本人妻久久久免费| 亚洲国产成人久久一区WWW| 久久国产精品99精品国产987| 精品久久久久久国产牛牛app| 亚洲国产精品无码成人片久久| 久久国产成人| 国产成人精品综合久久久| 国产一区二区精品久久| 少妇精品久久久一区二区三区| 国内精品伊人久久久影院| 四虎国产精品成人免费久久| 久久国产精品免费一区二区三区 | 久久人人爽人爽人人爽av| a级成人毛片久久| 久久青草国产手机看片福利盒子|