日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

DotNET多线程使用初探

發布時間:2023/12/13 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 DotNET多线程使用初探 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

最近幾周一直在做DotNET WinForm開發,陸陸續續有些收獲,希望能夠有空好好整理整理。記下來以免以后又忘了。:-)


?

一、最簡單的線程使用方法

新建一個C# Windows應用程序項目,在最前面的引用代碼那增加一行
using System.Threading;
在界面上扔個Button和Label,再寫幾行簡單的代碼,就是一個最簡單的線程例子啦
private void button1_Click(object sender, System.EventArgs e)
{
?Thread t = new Thread(new ThreadStart(myRun));
?t.Start();
}

private void myRun()
{
?for(int i=0; i<1000000; i++)
?{
??if (i % 1000 == 0)
???label1.Text = i.ToString();
?}
}

當然,這個例子沒有處理線程之間同步之類關系。你試試快速點幾下Button就知道有什么好玩的事情發生了。

二、給線程傳遞參數

?



ThreadStart 委托沒有參數也沒有返回值。其聲明為 public delegate void ThreadStart();
所以不能直接給線程傳遞參數。但是我們可以把線程函數封裝到一個類里,給類的實例傳遞參數(可以在創建實例時,也可以用另外的函數來傳遞。這不是重點)。因為DotNET自由線程的特點,在線程中是可以訪問同一個類里的數據的。
我們更改上面的簡單例子,嘗試給線程傳遞一個循環的終止值。
首先是弄個類把 myRun 函數裝進去 :-) 注意要公開函數(public)
?public class myThreadClass
?{
??private int Max = 0;
??public myThreadClass(int initValue)
??{
???Max = initValue;
??}

??public void myRun()
??{
???for(int i=0; i???{
????if (i % 1000 == 0)
?????label1.Text = i.ToString();
???}
??}
?}
然后,Button事件有點小改動,如下:
myThreadClass myThread = new myThreadClass(800000);
Thread t = new Thread(new ThreadStart(myThread.myRun));
t.Start();
僅僅是多了一行,很簡單是吧?

編譯,出錯啦!找不到類型或命名空間名稱"label1"
注意到我們原來是直接在Form實例中使用label1,現在將myRun裝到另外的類里,當然不能直接訪問label1啦。怎么辦?
一樣,弄成個參數,傳給myThreadClass就行。修改后的程序如下:
?public class myThreadClass
?{
??private int Max = 0;
??object obj = null;

??public myThreadClass(int initValue, object initObj)
??{
???Max = initValue;
???obj = initObj;
??}

??public void myRun()
??{
???for(int i=0; i???{
????if (i % 1000 == 0)
?????if (obj != null)
?????? (obj as Label).Text = i.ToString();
???}
??}
?}
下面是Form1中的按鈕事件
??private void button1_Click(object sender, System.EventArgs e)
??{
???myThreadClass myThread = new myThreadClass(800000, label1);
???Thread t = new Thread(new ThreadStart(myThread.myRun));
???t.Start();
??}
好了,運行下看看,是不是和原來的效果一模一樣。差別在于調用線程的時候,你可以傳遞參數,把握線程的運行時間。

三、獲得線程的返回值


第二部分解決了線程參數的問題,這部分我們來解決返回值的問題。
我們注意到,第二部分的代碼,會把線程的中間運行狀態的值寫到Form1的label1.Text中,那么,我們能不能從這里動手腳呢?試試看。
往Form1上扔個進度條ProgressBar先,myThreadClass我們暫時先不動,只改Button事件:
??private void button1_Click(object sender, System.EventArgs e)
??{
???const int Max = 800001;
???progressBar1.Maximum = Max;
???progressBar1.Value = 0;
???myThreadClass myThread = new myThreadClass(Max, label1);
???Thread t = new Thread(new ThreadStart(myThread.myRun));
???t.Start();
???while ( t.IsAlive )
???{
????progressBar1.Value = Int32.Parse(label1.Text.ToString());
????progressBar1.Refresh();
????Thread.Sleep(0);
???}
??}
運行一下,結果是不行!窗體完全失控了。如圖:


分析下原因。很顯然,是那個while搞的鬼!讓窗體主線程在這里不停的循環、執行。根本沒有多余的力氣來更新窗體界面顯示啦!

此路不通!那怎么辦好呢?答案就是 回調函數。
首先,聲明一個回調函數原型,在我們這個例子中,只需要取得一個返回值,所以回調函數的參數只有一個,如果有更多返回值,可相應修改。
namespace TestThread
{
?public delegate void ThreadCallback(int i);?

?public class Form1 : System.Windows.Forms.Form

然后修改myThreadClass類,不再需要傳遞label1給線程了。因為我們將在回調函數中獲得線程當前循環的值,然后由回調函數自個來更新label1.Text,同時還要更新progressBar1。
但要傳遞給線程的參數扔是兩個,一個是initValue用來控制循環的,一個是ThreadCallback callbackDelegate,即回調函數。修改后的myThreadClass類代碼如下:
?public class myThreadClass
?{
??private int Max = 0;
??private ThreadCallback callback;


??public myThreadClass(int initValue, ThreadCallback callbackDelegate)
??{
???Max = initValue;
???callback = callbackDelegate;
??}

??public void myRun()
??{
???for(int i=0; i???{
????if (i % 1000 == 0)
?????if (callback != null)
?????? callback(i);
???}
??}
?}

回到Form1,先寫個回調函數ThreadCallback 的具體實現
??public void myCallback(int i)
??{
???label1.Text = i.ToString();
???label1.Refresh();
???progressBar1.Value = i;
???progressBar1.Refresh();
??}
接著修改Button事件
??private void button1_Click(object sender, System.EventArgs e)
??{
???const int Max = 800001;
???progressBar1.Maximum = Max;
???progressBar1.Value = 0;
???myThreadClass myThread = new myThreadClass(Max, new ThreadCallback(myCallback));
???Thread t = new Thread(new ThreadStart(myThread.myRun));
???t.Start();
??}
代碼中,通過new ThreadCallback(myCallback),給線程傳了回調函數。

OK!
改動都不算多。我們運行下看看吧!一切順利!如圖:

label1和progressBar1同步更新狀態。而且在線程運行時,拖動主窗體也不會失去控制了,沒有任何問題。

后文


本文是《DotNET多線程使用初探》,故不是詳細的DotNET多線程使用說明。多線程還有很多其它方面,如生存期、線程間同步、死鎖問題、STA、MTA、線程池等等等等。
本文起源于我在DotNET開發中,處理一些復雜的數據庫操作非常耗時,主窗體經常失去反應。這時就需要一些簡單的線程操作。很必要的一個是給用戶一個進度條。
如果你遇到的情況跟我相似,相信本文對你會有所幫助。

?

轉載于:https://www.cnblogs.com/CrazyWill/archive/2005/08/25/222579.html

總結

以上是生活随笔為你收集整理的DotNET多线程使用初探的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。