2016-04-28 16 views
2

シンプルなコードを使って、C#でメソッドを非同期的に呼び出す方法を理解しようとしています。非同期に同期メソッドを呼び出す

私は私が私が通常(同期)を実行したい第2の機能機能2を持っているそして、非同期

static void Function1(out int threadId) 
{ 
    Console.WriteLine("I'm inside Function 1. Going to sleep for 7 seconds..."); 
    Thread.Sleep(7000); 
    Console.WriteLine("I'm awake now"); 
    threadId = Thread.CurrentThread.ManagedThreadId; 
} 

を実行したい機能1と呼ばれる機能も

static void Function2() 
{ 
    Thread.Sleep(3000); 
    Console.WriteLine("I'm inside Function 2"); 
} 

Iを持っていますFunction1と同じメソッドシグネチャを持つデリゲートを作成しました。

delegate void AsyncMethodCaller(out int threadId); 

そしてここでは、私のメインの呼び出し方法であって、私のメインの方法では

static void Main(string[] args) 
{ 
    int threadId; 
    AsyncMethodCaller caller = new AsyncMethodCaller(Function1); 
    caller.BeginInvoke(out threadId, null, null); 
    Function2(); 
} 

、私は機能1が非同期に実行を開始することを期待。 を待たずに終了すると、Function2が実行されます。だから私は、次の出力を期待:

私は7 秒間寝る非同期機能1.内部のよ...
私は機能2
内だ私は今

目を覚ましてよ

代わりに、私は次の出力を得る:私は機能2

内だ
...私は7 秒間寝る非同期機能1.内側だ

なぜ私の期待は現実と異なるのですか?なぜ私は目が覚めているのですか?

は、.NETのための基本的なプロセスの有効期間のルールがすべてフォアグラウンドスレッドが終了したときに、プロセスが終了することにしているあなたに

+0

メイン – MickyD

+0

が@MickyDに同意する前に、Function1が完了するのを待つことがないためです。 –

+0

メソッドを非同期に呼び出すたびにデリゲートを作成する必要がありますか? – IsaacBok

答えて

4

ありがとうございます。バックグラウンドスレッドは単に打ち切られます。プロセスはそれらを待つことはありません。

さらに、デリゲートのBeginInvoke()メソッドを呼び出すと、暗黙的に、スレッドプールを使用してデリゲートが呼び出されます。スレッドプールは完全にバックグラウンドスレッドで作られています。

つまり、BeginInvoke()を呼び出すと、それ自体の寿命を保証しないスレッドを使用して.NETに代理人を呼び出すように指示します。 Function2()を呼び出した直後に発生する、プロセスの単一のメインフォアグラウンドスレッドが終了すると、そのスレッドは中断できます(この場合はそうです)。

非同期に呼び出されたデリゲートを正常に完了させるには、明示的に待機する必要があります。例えば。:非同期的に呼び出されたデリゲートが完了するまで

IAsyncResult result = caller.BeginInvoke(out threadId, null, null); 

Function2(); 

caller.EndInvoke(out threadId, result); 

EndInvoke()方法は、それが呼び出しが完了する前にデリゲートを呼び出すために使用されるスレッドが中止されていないことを確実にするために起こるとするためにメインスレッドを待機させることができ、ブロックします。

コード例の構造は、既にMSDNのCalling Synchronous Methods Asynchronouslyを見てきたことを示唆していますが、このページに言及していない場合は、これを処理する方法の説明に役立つ多くの詳細が含まれています特定のシナリオ。

+1

は、 'BeginInvoke()'メソッドを使用せずにFunction1を非同期に呼び出す方法はありますか? – IsaacBok

+1

確かに。実際、 'BeginInvoke()'を使うのはおそらく、メソッドを非同期的に実行する最も一般的な方法ではありません。もっと典型的な例は、コールを 'Task'にラップすることです。例えば。 'タスクタスク= Task.Run(()=> Function1(スレッドID)); Function2(); task.Wait(); 'は上記と同じですが、代わりに' Task'を使います。このようにすると、カスタムAsyncMethodCallerデリゲート型を宣言する必要はありません。デリゲートインスタンスのターゲットではなく、匿名メソッドによって直接呼び出されるためです。 –

+0

パーフェクト!ありがとう@Peter Duniho – IsaacBok