続・デリゲートの非同期呼び出し
メソッドを非同期呼び出ししたものの、その後どこかで同期したい場合のやり方。
BeginInvokeの戻りとして、System.Runtime.Remoting.Messaging.AsyncResult型が戻されるので、こいつのメンバIsCompletedを使います。
AsyncResult.IsCompleted説は完全にウソでした。。
IsCompletedは
Gets a value indicating whether the server has completed the call.
ということで、呼び出しが終わった段階でtrueになってしまうので、コールバック関数の完了まで保証してくれません。というわけで、自前のIsCompletedを用意して、コールバック関数の終了時にtrueにするようにしました。これなら確実。
でも、WaitHandleとかいうのを使えばできそう?要追加調査だなこりゃ。
以下、単純化のため、マルチキャストじゃないデリゲートを使ったサンプル。
using System; using System.Threading; using System.Runtime.Remoting.Messaging; class FunctionPointer { private static Boolean IsCompleted = false; public delegate int twoitem(int a, int b); public static int add(int a, int b) { return a + b; } private static void DisplayResult(IAsyncResult ar) { // キャストして元のデリゲートを取得する FunctionPointer.twoitem ptr = (FunctionPointer.twoitem)ar.AsyncS tate; int result = ptr.EndInvoke(ar); Console.WriteLine("result = {0}", result); IsCompleted = true; } static void Main(string[] args) { // 関数ポインタを定義 FunctionPointer.twoitem fp; fp = FunctionPointer.add; AsyncResult ar = (AsyncResult)fp.BeginInvoke(5, 3, new AsyncCall back(DisplayResult), fp); Console.WriteLine("非同期呼び出し完了"); while(!IsCompleted) { Thread.Sleep(100); } } }
結果はこう。
非同期呼び出し完了 result = 8
場合によっては、逆順に出ることもあり。
つまり、
Console.WriteLine("非同期呼び出し完了");
の行はデリゲートとは非同期に行われる(デリゲートの処理の完了に関わらず行われる)が、Mainメソッドの終了は、デリゲートと同期に行われるというわけです。