以SOCKET通信中的異步方法為例:
public static ManualResetEvent ConnectDone = new ManualResetEvent(false);
public static void ConnectCallback(IAsyncResult ar)
{
Socket sClient = (Socket)ar.AsyncState;
sClient.EndConnect(ar);
Console.WriteLine("Socket connected to {0}", sClient.RemoteEndPoint.ToString());
ConnectDone.Set();
}
public static void Main(string[] arg)
{
try
{
ipHostEntry ipHost = Dns.Resolve("127.0.0.1");
IPAddress ipAddr = ipHost.AddressList[0];
IPEndPoint endPoint = new IPEndPoint(ipAddr, 11000);
Socket sClient = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, PRotocolType.Tcp);
sClient.BeginConnect(endPoint, new AsyncCallback(ConnectCallback),
sClient);
for (int i = 0; i <5; i++)
Console.WriteLine("Do Some Other Work.");
byte[] byteData = Encoding.ASCII.GetBytes("Some Data.");
ConnectDone.WaitOne();
sClient.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(SendCallback), sClient);
………
}
(注:ManualResetEvent 允許線程通過發信號互相通信。通常,此通信涉及一個線程在其他線程進行之前必須完成的任務。
ManualResetEvent就像一個信號燈,可以利用它的信號來通知其它線程。它有幾個重要的方法:Reset(),Set(),WaitOne()。初始化該對象時,用戶可以指定其默認的狀態(有信號/無信號),在初始化以后,該對象將保持原來的狀態不變直到它的Reset()或者Set()方法被調用,Reset()方法將其設置為無信號狀態,Set()方法將其設置為有信號狀態。WaitOne()方法使當前線程掛起直到ManualResetEvent對象處于有信號狀態,此時該線程將被激活。)
本例中,主線程調用ConnectDone.WaitOne();后,主線程阻塞,直到連接操作(即ConnectCallback)完成,因為連接操作完成之后,執行了ConnectDone.Set()將信號燈設置為有信號,由于調用了ManualResetEvent.WaitOne()方法而處在等待狀態的主線程將接收到這個信號,于是它接著往下執行,完成后邊的工作。
同步與異步:
簡單地說,同步即程序執行一個方法,等該方法返回之后,繼續往下走,
異步:即程序調用一個方法后立即返回,“宏觀”而言,主線程與方法線程并行執行。
就本例而言,socket的異步方法BeginConnect被調用后,接著執行主線程中該語句之后的代碼,即:
for (int i = 0; i <5; i++)
Console.WriteLine("Do Some Other Work.");
byte[] byteData = Encoding.ASCII.GetBytes("Some Data.");
如果調用的是同步方法,那么,輸出“Socket connected to…”一定會在“Do Some Other Work.”之前,因為主線程必須等待同步方法的返回,但是在異步的情況下,將可能在5行“Do Some Other Work.”之間的某個時刻出現“Socket connected to…”的輸出(實際情況還依賴于操作系統的線程調度)。
至于在sClient.BeginSend(…)方法之前調用ConnectDone.WaitOne(),則是由于前者依賴于連接操作(即ConnectCallback)的完成,須得同步一下。
新聞熱點
疑難解答