.NET Framework 和第三方類庫中的類型可以提供允許應用程序在主應用程序線程之外的線程中執行異步操作的同時繼續執行的方法。下面幾部分介紹了在調用使用 IAsyncResult 設計模式的異步方法時可以采用的幾種不同方式,並提供了演示這些方式的代碼示例。
通過結束異步操作來阻止應用程序執行
如果應用程序在等待異步操作結果時不能繼續執行其他工作,則在操作完成之前,必須阻止執行其他工作。可以使用下列方法之一來在等待異步操作完成時阻止應用程序的主線程。
-
調用異步操作的 EndOperationName 方法。本主題中演示了此方法。
-
使用異步操作的 BeginOperationName 方法返回的 IAsyncResult 的 AsyncWaitHandle 屬性。有關演示此方法的示例,請參見使用 AsyncWaitHandle 阻止應用程序的執行。
在異步操作完成之前使用 EndOperationName 方法阻止的應用程序通常會調用 BeginOperationName 方法,執行任何不需要等待異步操作的結果也可以執行的工作,然后調用 EndOperationName。
示例
下面的代碼示例演示如何使用 Dns 類中的異步方法來檢索用戶指定的計算機的域名系統信息。請注意,示例中為 BeginGetHostByNamerequestCallback 和 stateObject 參數傳遞了 null(在 Visual Basic 中為 Nothing),因為在使用此方法時不需要這兩個參數。
/* The following example demonstrates using asynchronous methods to get Domain Name System information for the specified host computer. */ using System; using System.Net; using System.Net.Sockets; namespace Examples.AdvancedProgramming.AsynchronousOperations { public class BlockUntilOperationCompletes { public static void Main(string[] args) { // Make sure the caller supplied a host name. if (args.Length == 0 || args[0].Length == 0) { // Print a message and exit. Console.WriteLine("You must specify the name of a host computer."); return; } // Start the asynchronous request for DNS information. // This example does not use a delegate or user-supplied object // so the last two arguments are null. IAsyncResult result = Dns.BeginGetHostEntry(args[0], null, null); Console.WriteLine("Processing your request for information..."); // Do any additional work that can be done here. try { // EndGetHostByName blocks until the process completes. IPHostEntry host = Dns.EndGetHostEntry(result); string[] aliases = host.Aliases; IPAddress[] addresses = host.AddressList; if (aliases.Length > 0) { Console.WriteLine("Aliases"); for (int i = 0; i < aliases.Length; i++) { Console.WriteLine("{0}", aliases[i]); } } if (addresses.Length > 0) { Console.WriteLine("Addresses"); for (int i = 0; i < addresses.Length; i++) { Console.WriteLine("{0}",addresses[i].ToString()); } } } catch (SocketException e) { Console.WriteLine("An exception occurred while processing the request: {0}", e.Message); } } } }
使用 AsyncWaitHandle 阻止應用程序的執行
如果應用程序在等待異步操作結果時不能繼續執行其他工作,則在操作完成之前,必須阻止執行其他工作。可以使用下列方法之一來在等待異步操作完成時阻止應用程序的主線程。
-
使用異步操作的 BeginOperationName 方法返回的 IAsyncResult 的 AsyncWaitHandle 屬性。本主題中演示了此方法。
-
調用異步操作的 EndOperationName 方法。有關演示此方法的示例,請參見通過結束異步操作來阻止應用程序執行。
那些在異步操作完成前一直使用一個或多個 WaitHandle 對象阻止其他操作的應用程序通常會調用 BeginOperationName 方法,執行不需要等待操作結果的工作,然后一直等到異步操作完成才停止阻止。通過使用 AsyncWaitHandle 調用 WaitOne 方法之一,應用程序可以阻止一個操作。若要在等待一組異步操作完成期間阻止執行,應將相關的 AsyncWaitHandle 對象存儲在數組中,然后調用 WaitAll 方法之一。若要在等待一組異步操作中的任一操作完成時阻止其他操作,應將關聯的 AsyncWaitHandle 對象存儲在數組中,然后調用 WaitAny 方法之一。
示例
下面的代碼示例演示如何使用 DNS 類中的異步方法來檢索用戶指定的計算機的域名系統信息。此示例演示如何使用與異步操作關聯的 WaitHandle 來阻止。請注意,示例中為 BeginGetHostByNamerequestCallback 和 stateObject 參數傳遞了 null(在 Visual Basic 中為 Nothing),因為使用此方法時不需要這兩個參數。
/* The following example demonstrates using asynchronous methods to get Domain Name System information for the specified host computer. */ using System; using System.Net; using System.Net.Sockets; using System.Threading; namespace Examples.AdvancedProgramming.AsynchronousOperations { public class WaitUntilOperationCompletes { public static void Main(string[] args) { // Make sure the caller supplied a host name. if (args.Length == 0 || args[0].Length == 0) { // Print a message and exit. Console.WriteLine("You must specify the name of a host computer."); return; } // Start the asynchronous request for DNS information. IAsyncResult result = Dns.BeginGetHostEntry(args[0], null, null); Console.WriteLine("Processing request for information..."); // Wait until the operation completes. result.AsyncWaitHandle.WaitOne(); // The operation completed. Process the results. try { // Get the results. IPHostEntry host = Dns.EndGetHostEntry(result); string[] aliases = host.Aliases; IPAddress[] addresses = host.AddressList; if (aliases.Length > 0) { Console.WriteLine("Aliases"); for (int i = 0; i < aliases.Length; i++) { Console.WriteLine("{0}", aliases[i]); } } if (addresses.Length > 0) { Console.WriteLine("Addresses"); for (int i = 0; i < addresses.Length; i++) { Console.WriteLine("{0}",addresses[i].ToString()); } } } catch (SocketException e) { Console.WriteLine("Exception occurred while processing the request: {0}", e.Message); } } } }
輪詢異步操作的狀態
在等待異步操作結果的同時可以進行其他工作的應用程序不應在操作完成之前阻止等待。可以使用下列方法之一來在等待異步操作完成的同時繼續執行指令。
-
可使用異步操作的 BeginOperationName 方法返回的 IAsyncResult 的 IsCompleted 屬性來確定此操作是否已完成。此方法叫做輪詢;本主題中將演示輪詢。
-
可使用 AsyncCallback 委托來處理另一個線程中的異步操作的結果。有關演示此方法的示例,請參見使用 AsyncCallback 委托結束異步操作。
示例
下面的代碼示例演示如何使用 Dns 類中的異步方法來檢索用戶指定的計算機的域名系統信息。此示例開始異步操作,然后在控制台輸出句點(“.”),直到操作完成。請注意,示例中為 BeginGetHostByNameAsyncCallback 和 Object 參數傳遞了 null(在 Visual Basic 中為 Nothing),因為在使用此方法時不需要這兩個參數。
/* The following example demonstrates using asynchronous methods to get Domain Name System information for the specified host computer. This example polls to detect the end of the asynchronous operation. */ using System; using System.Net; using System.Net.Sockets; using System.Threading; namespace Examples.AdvancedProgramming.AsynchronousOperations { public class PollUntilOperationCompletes { static void UpdateUserInterface() { // Print a period to indicate that the application // is still working on the request. Console.Write("."); } public static void Main(string[] args) { // Make sure the caller supplied a host name. if (args.Length == 0 || args[0].Length == 0) { // Print a message and exit. Console.WriteLine("You must specify the name of a host computer."); return; } // Start the asychronous request for DNS information. IAsyncResult result = Dns.BeginGetHostEntry(args[0], null, null); Console.WriteLine("Processing request for information..."); // Poll for completion information. // Print periods (".") until the operation completes. while (result.IsCompleted != true) { UpdateUserInterface(); } // The operation is complete. Process the results. // Print a new line. Console.WriteLine(); try { IPHostEntry host = Dns.EndGetHostEntry(result); string[] aliases = host.Aliases; IPAddress[] addresses = host.AddressList; if (aliases.Length > 0) { Console.WriteLine("Aliases"); for (int i = 0; i < aliases.Length; i++) { Console.WriteLine("{0}", aliases[i]); } } if (addresses.Length > 0) { Console.WriteLine("Addresses"); for (int i = 0; i < addresses.Length; i++) { Console.WriteLine("{0}",addresses[i].ToString()); } } } catch (SocketException e) { Console.WriteLine("An exception occurred while processing the request: {0}", e.Message); } } } }
使用 AsyncCallback 委托結束異步操作
在等待異步操作結果的同時可以進行其他工作的應用程序不應在操作完成之前阻止等待。可以使用下列方法之一來在等待異步操作完成的同時繼續執行指令。
-
可使用 AsyncCallback 委托來處理另一個線程中的異步操作的結果。本主題中演示了此方法。
-
可使用異步操作的 BeginOperationName 方法返回的 IAsyncResult 的 IsCompleted 屬性來確定此操作是否已完成。有關演示此方法的示例,請參見輪詢異步操作的狀態。
示例
下面的代碼示例演示如何使用 Dns 類中的異步方法來檢索用戶指定的計算機的域名系統 (DNS) 信息。此示例創建了引用 ProcessDnsInformation 方法的 AsyncCallback 委托。對各個針對 DNS 信息發出的異步請求,將分別調用一次此方法。
請注意,用戶指定的主機被傳遞給了 BeginGetHostByNameObject 參數。有關演示如何定義和使用更復雜的狀態對象的示例,請參見使用 AsyncCallback 委托和狀態對象。
/* The following example demonstrates using asynchronous methods to get Domain Name System information for the specified host computers. This example uses a delegate to obtain the results of each asynchronous operation. */ using System; using System.Net; using System.Net.Sockets; using System.Threading; using System.Collections.Specialized; using System.Collections; namespace Examples.AdvancedProgramming.AsynchronousOperations { public class UseDelegateForAsyncCallback { static int requestCounter; static ArrayList hostData = new ArrayList(); static StringCollection hostNames = new StringCollection(); static void UpdateUserInterface() { // Print a message to indicate that the application // is still working on the remaining requests. Console.WriteLine("{0} requests remaining.", requestCounter); } public static void Main() { // Create the delegate that will process the results of the // asynchronous request. AsyncCallback callBack = new AsyncCallback(ProcessDnsInformation); string host; do { Console.Write(" Enter the name of a host computer or <enter> to finish: "); host = Console.ReadLine(); if (host.Length > 0) { // Increment the request counter in a thread safe manner. Interlocked.Increment(ref requestCounter); // Start the asynchronous request for DNS information. Dns.BeginGetHostEntry(host, callBack, host); } } while (host.Length > 0); // The user has entered all of the host names for lookup. // Now wait until the threads complete. while (requestCounter > 0) { UpdateUserInterface(); } // Display the results. for (int i = 0; i< hostNames.Count; i++) { object data = hostData [i]; string message = data as string; // A SocketException was thrown. if (message != null) { Console.WriteLine("Request for {0} returned message: {1}", hostNames[i], message); continue; } // Get the results. IPHostEntry h = (IPHostEntry) data; string[] aliases = h.Aliases; IPAddress[] addresses = h.AddressList; if (aliases.Length > 0) { Console.WriteLine("Aliases for {0}", hostNames[i]); for (int j = 0; j < aliases.Length; j++) { Console.WriteLine("{0}", aliases[j]); } } if (addresses.Length > 0) { Console.WriteLine("Addresses for {0}", hostNames[i]); for (int k = 0; k < addresses.Length; k++) { Console.WriteLine("{0}",addresses[k].ToString()); } } } } // The following method is called when each asynchronous operation completes. static void ProcessDnsInformation(IAsyncResult result) { string hostName = (string) result.AsyncState; hostNames.Add(hostName); try { // Get the results. IPHostEntry host = Dns.EndGetHostEntry(result); hostData.Add(host); } // Store the exception message. catch (SocketException e) { hostData.Add(e.Message); } finally { // Decrement the request counter in a thread-safe manner. Interlocked.Decrement(ref requestCounter); } } } }
