程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 多線程的應用小結,多線程應用小結

多線程的應用小結,多線程應用小結

編輯:C#入門知識

多線程的應用小結,多線程應用小結


一、使用多線程的幾種方式

 

其他組件的BeginXXX和EndXXX方法

在其他的.net組件中也有類似BeginInvoke和EndInvoke的方法,如System.Net.HttpWebRequest類的BeginGetResponse和EndGetResponse方法。其使用方法類似於委托類型的BeginInvoke和EndInvoke方法,例如:

class Program

{

//回調函數

private static void requestCompleted(IAsyncResult asyncResult)

{

if (asyncResult == null || asyncResult.AsyncState==null)

{

Console.WriteLine("回調失敗");

return;

}

HttpWebRequest hwr = asyncResult.AsyncState as HttpWebRequest;

HttpWebResponse response = (HttpWebResponse)hwr.EndGetResponse(asyncResult);

StreamReader sr = new StreamReader(response.GetResponseStream());

string str = sr.ReadToEnd();

Console.WriteLine("返回流長度:"+str.Length);

}

static void Main(string[] args)

{

HttpWebRequest request =

(HttpWebRequest)WebRequest.Create("http://www.baidu.com");

//異步請求

IAsyncResult asyncResult = request.BeginGetResponse(requestCompleted, request);

Console.WriteLine("任務開始");

Console.Read();

}

}

二、線程的狀態控制

 

 

由委托啟動的線程的狀態控制

委托的EndInvoke方法阻止當前線程運行,直到委托異步執行完成。

IAsyncResult.IsCompleted屬性表示委托異步執行是否完成。

委托的WaitOne方法等待異步方法執行完成。

三、多線程訪問GUI界面的處理

 

 

使用BackgroundWorker組件

主要的事件及參數:

1.DoWork—當執行BackgroundWorker.RunWorkerAsync方法時會觸發該事件,並且傳遞DoWorkEventArgs參數;

2.ProgressChanged—操作處理中獲得的處理狀態變化,通過BackgroundWorker.ReportProgress方法觸發該事件,並且傳遞ProgressChangedEventArgs,其中包含了處理的百分比,這個參數在UI界面上設置progressbar控件。

3.RunWorkerCompleted—異步操作完成或中途終止會觸發該事件。如果需要提前終止執行後台操作,可以調用BackgroundWorker.CancelAsync方法。在處理DoWork事件的函數中檢測BackgroundWorker.CancellationPending屬性是否為true,如果是true,則表示用戶已經取消了異步調用,同時將DoWorkEventArgs.Cancel屬性設為true(傳遞給處理DoWork事件的函數的第二個參數),這樣當退出異步調用的時候,可以讓處理RunWorkerCompleted事件的函數知道是正常退出還是中途退出。

主要的方法:

1. BackgroundWorker.RunWorkerAsync—"起動"異步調用的方法有兩次重載RunWorkerAsync(),RunWorkerAsync(object argument),第二個重載提供了一個參數,可以供異步調用使用。(如果有多個參數要傳遞怎麼辦,使用一個類來傳遞他們吧)。調用該方法後會觸發DoWork事件,並且為處理DoWork事件的函數傳遞DoWorkEventArg參數,其中包含了RunWorkerAsync傳遞的參數。在相應DoWork的處理函數中就可以做具體的復雜操作。

2. BackgroundWorker.ReportProgress—需要在一個冗長的操作中向用戶不斷反饋進度,這樣的話就可以調用的ReportProgress(int percent),在調用 ReportProgress 方法時,觸發ProgressChanged事件。提供一個在 0 到 100 之間的整數,它表示後台活動已完成的百分比。你也可以提供任何對象作為第二個參數,允許你給事件處理程序傳遞狀態信息。作為傳遞到此過程的 ProgressChangedEventArgs 參數屬性,百分比和你自己的對象(如果提供的話)均要被傳遞到 ProgressChanged 事件處理程序。這些屬性被分別命名為 ProgressPercentage 和 UserState,並且你的事件處理程序可以以任何需要的方式使用它們。(注意:只有在BackgroundWorker.WorkerReportsProgress屬性被設置為true該方法才可用)。

3. BackgroundWorker.CancelAsync—但需要退出異步調用的時候,就調用的這個方法。但是樣還不夠,因為它僅僅是將BackgroudWorker.CancellationPending屬性設置為true。你需要在具體的異步調用處理的時候,不斷檢查BackgroudWorker.CancellationPending是否為true,如果是真的話就退出。(注意:只有在BackgroundWorker.WorkerSupportsCancellation屬性被設置為true該方法才可用)。

//按鈕事件

private void button1_Click(object sender, EventArgs e)

{

this.backgroundWorker1.RunWorkerAsync();//處理事務

}

//處理事務事件

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)

{

//初始化進度條

this.progressBar1.Maximum = 100;

this.progressBar1.Minimum = 0;

//模擬事物處理

for (int i = 0; i < 100; i++)

{

Thread.Sleep(10);

//局部操作完成事件觸發

this.backgroundWorker1.ReportProgress(i, null);

}

}

//局部操作完成時執行的方法

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)

{

this.progressBar1.Value = e.ProgressPercentage;//設置進度條值

}

//事物處理完成時觸發

private void backgroundWorker1_RunWorkerCompleted(object sender,RunWorkerCompletedEventArgs e)

{

MessageBox.Show(null, "工作線程完成!", "提示");

}

四、線程池

 

 

線程池的使用

class Program

{

//線程方法

public static void ThreadProc(object i)

{

Console.WriteLine(i.ToString());

Thread.Sleep(1000);

}

public static void Main()

{

ThreadPool.SetMaxThreads(3, 3);//設置線程池

for (int i = 0; i < 10; i++)

{

ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc), "線程" + i);

}

Console.WriteLine("運行結束");

Console.Read();

}

}

每一個進程都有一個線程池,線程池的默認大小是25,我們可以通過SetMaxThreads方法來設置其最大值。

注意:因為WaitCallback委托的原型是void WaitCallback(object state),那沒有辦法,我們只能將多個參數封裝到一個Object中。

五、線程同步

 

 

使用Semaphore

Semaphore類:限制可同時訪問某一資源或資源池的線程數。

class Program

{

private static Semaphore semaphore = new Semaphore(0, 5);//初始化信號量

static void Main(string[] args)

{

for (int i = 0; i < 10; i++)

{

Thread thread = new Thread(Method);

thread.Start("線程" + i);

}

semaphore.Release(2);//釋放信號量2個

Console.WriteLine("主線程運行完畢!");

Console.Read();

}

  //線程執行方法

private static void Method(object o)

{

semaphore.WaitOne();//等待信號量

Thread.Sleep(1000);

Console.WriteLine(o.ToString());

semaphore.Release();//釋放信號量

}

}

其它的線程只有等到主線程釋放才會執行,因為我給信號量計數器的初始值是0,所以其它線程在主線程釋放前都會被阻塞。而後,我在主線程直接用Release(2)函數將計數器置為2,所以2個線程可以同時得到執行。

注意:可以給信號量設置一個名稱,這個名稱是操作系統可見的,因此,可以使用這些信號量來協調跨進程邊界的資源使用。

class Program

{

  static void Main(string[] args)

{

//初始信號量5個,最多信號量10個

Semaphore seamphore = new Semaphore(5, 10, "Test");

seamphore.WaitOne();//等待信號

Console.WriteLine("獲取信號量 1");

seamphore.WaitOne();//等待信號

Console.WriteLine("獲取信號量 2");

seamphore.WaitOne();//等待信號

Console.WriteLine("獲取信號量 3");

Console.WriteLine("主線程運行完畢!");

Console.Read();

}

}

運行兩個這樣的程序,結果如下,在第二個運行的示例中,會將阻塞在第三個信號量上:

六、定時器Timer

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved