在應屆生找工作的時候,多線程操作幾乎是所有的公司都會問及的一個基本問題。
這裡做了一個多線程操作的總結,這裡總結了通過異步委托來實現多線程操作。
定義一個委托,是創建一個線程的最簡單的方法,並且異步調用它。委托是方法的類型安全的引用。同時委托還智齒異步調用方法。
委托使用線程池來完成異步任務。
當自己的程序使用異步委托的時候,委托會自動創建ige執行線程的任務。委托使用線程池完成異步任務,所有的異步委托調用,都會通過調用系統線程池中的線程來完成調用異步任務。
在下面的簡單例子中,我們定義了一個異步委托,並在每次輸出的時候顯示該函數運行在哪個線程中。
在異步委托中,可以使用三種技術來異步的調用委托。下面分別介紹三種調用異步委托的方法。
1. 投票判斷異步委托是否完成
在委托中調用BeginInvoke()方法,返回IAsyncResult結果。程序的源代碼如下:
[csharp]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace AsyncDelegate
{
class Program
{
public delegate int TakeSomeTimeDelegate(int data,int ms);
static void Main(string[] args)
{
TakeSomeTimeDelegate dl=TakeSomeTime;
IAsyncResult ar=dl.BeginInvoke(1,200,null,null);
while (!ar.IsCompleted)
{
Console.WriteLine(".");
Console.WriteLine("Run in thread:" + Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(50);
}
int result = dl.EndInvoke(ar);
Console.WriteLine("Result:{0}", result);
}
static int TakeSomeTime(int data, int ms)
{
Console.WriteLine("TakeSomeTime started!");
Console.WriteLine("Run in thread:"+Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(ms);
Console.WriteLine("TakeSomeTime Completed!");
return ++data;
}
}
}
該程序的輸出結果如圖:
可以看到主線程和異步委托線程是同時執行的。
如果在委托結束之前不等待委托完成其他任務就結束主線程,委托線程就會停止。
int result = dl.EndInvoke(ar); 這裡的EndInvoke()函數會一直等在異步委托完成並在異步委托完成之前阻斷主線程。這樣就可以通過這個函數保證異步委托能夠正確完成。
2. 等待句柄判斷異步委托完成
通過AsyncWatiHandle屬性,訪問等待句柄。WaitOne()方法阻斷當前線程,直到異步調用線程完成返回可以利用的句柄以後再執行當前線程。
程序:
[html]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace AsyncDelegate
{
class Program
{
public delegate int TakeSomeTimeDelegate(int data,int ms);
static void Main(string[] args)
{
TakeSomeTimeDelegate dl=TakeSomeTime;
IAsyncResult ar=dl.BeginInvoke(1,200,null,null);
while (true)
{
Console.WriteLine(".");
Console.WriteLine("Run in thread:" + Thread.CurrentThread.ManagedThreadId);
if (ar.AsyncWaitHandle.WaitOne(100, false))
{
Console.WriteLine("Can get the result now");
break;
}
}
//while (!ar.IsCompleted)
//{
// Console.WriteLine(".");
// Console.WriteLine("Run in thread:" + Thread.CurrentThread.ManagedThreadId);
// Thread.Sleep(50);
//}
int result = dl.EndInvoke(ar);
Console.WriteLine("Result:{0}", result);
}
static int TakeSomeTime(int data, int ms)
{
Console.WriteLine("TakeSomeTime started!");
Console.WriteLine("Run in thread:"+Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(ms);
Console.WriteLine("TakeSomeTime Completed!");
return ++data;
}
}
}
運行結果:
ar.AsyncWaitHandle.WaitOne()阻斷了當前線程, 直到異步調用線程完成獲得可以利用的句柄以後再次執行當前線程。
3. 利用異步回調函數判斷異步調用線程是否結束
回調函數的操作比較復雜, 而且對於程序的理解和維護造成非常大的困難。所以一般情況下能不用回調函數就不要使用回調函數。
使用回調函數,必須注意這個函數從委托線程中調用,而不是從主線程中調用回調函數。
[csharp]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace AsyncDelegate
{
class Program
{
public delegate int TakeSomeTimeDelegate(int data,int ms);
static void Main(string[] args)
{
TakeSomeTimeDelegate dl=TakeSomeTime;
IAsyncResult ar = dl.BeginInvoke(1, 200, TakeSomeTimeCompleted, dl);
for (int i = 0; i < 10;i++ )
{
Console.WriteLine(".");
Console.WriteLine("Run in thread:" + Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(50);
}
//int result = dl.EndInvoke(ar);
//Console.WriteLine("Result:{0}", result);
}
static int TakeSomeTime(int data, int ms)
{
Console.WriteLine("TakeSomeTime started!");
Console.WriteLine("Run in thread:"+Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(ms);
Console.WriteLine("TakeSomeTime Completed!");
return ++data;
}
static void TakeSomeTimeCompleted(IAsyncResult ar)
{
if (ar==null)
{
throw new ArgumentNullException("ar");
}
TakeSomeTimeDelegate dl = ar.AsyncState as TakeSomeTimeDelegate;
int result = dl.EndInvoke(ar);
Console.WriteLine("result : {0}", result);
//Console.WriteLine("Run in thread:" + Thread.CurrentThread.ManagedThreadId);
}
}
}
運行結果: