2009-03-18 10 views
8

イベントのサブスクライバが多いコンポーネントで非同期イベントディスパッチを行うためのオプションを探しています。オプションを熟読で、私はこの例に出くわしました:これは重大なリソースリークであるように、古い構文を越えてイベントを非同期で発生させる

public event ValueChangedEvent ValueChanged; 
public void FireEventAsync(EventArgs e) 
{ 
    Delegate[] delegates = ValueChanged.GetInvocationList(); 
    foreach (Delegate d in delegates) 
    { 
     ValueChangedEvent ev = (ValueChangedEvent)d; 
     ev.BeginInvoke(e, null, null); 
    } 
} 

を(サンプルは、.NET 1.1からだった)、それは私には見えます。完了方法、完了のためのポーリング、またはEndInvokeが呼び出されるその他の方法はありません。

BeginInvokeはすべてに対応するEndInvokeである必要があります。さもなければ、非同期イベントの間に発生した(潜在的に)例外とともに、保留中のオブジェクトインスタンスが浮動しています(AsyncResult)。

コールバックを指定してEndInvokeを実行するだけで、それを変更するのは簡単ですが、必要がない場合は簡単です。 。 。

非同期例外の処理はまったく別の問題であり、UIスレッド(つまりInvokeRequiredなど)との同期の必要性と相まって、これらの非同期通知を実行する考えは非常によく機能します。

ので、二つの質問:私はすべてのBeginInvokeEndInvokeに対応する必要があることを信じるに修正

  1. アム?
  2. 上記以外にも、Windowsフォームアプリケーションで非同期イベント通知を行う際に、他の落とし穴がありますか?戻り型が指定されている場合
+0

なぜ非同期でディスパッチしたいのですか?これが有益であることを示すパフォーマンス分析を行ったことがありますか?もしそうでなければ、複数のスレッドがそれを悪化させるかもしれません。 –

+0

はい、パフォーマンス分析を行って、非同期処理が利益になるかどうかを判断しました。 –

答えて

3

BeginInvoke()への呼び出しはEndInvoke()とペアにする必要がありますが、それをやっていないと、リソースリークにはなりません。 BeginInvoke()によって返されたIAsyncResultはガベージコレクションされます。

このコードの最大の落とし穴は、アプリケーションを終了する例外に非常に晒されていることです。デリゲート呼び出しを例外ハンドラにラップし、発生した例外をどのように伝播したいかを考えてみましょう(最初の報告、集約例外の生成など)。

BeginInvoke()を使用して削除を呼び出すと、スレッドをスレッドキューから取り出してイベントの実行を開始します。つまり、イベントは常にメインのUIスレッドから起動されます。これにより、いくつかのイベントハンドラのシナリオを扱いにくくすることができます(UIの更新など)。ハンドラは、SynchronizationContext.Send()または.Post()を呼び出してプライマリUIスレッドと同期する必要があることを認識する必要があります。もちろん、他のすべてのマルチスレッドプログラミングの落とし穴も当てはまります。

+0

ええ、クライアント(つまりイベント加入者)がプールスレッドの通知を処理できるように準備するという要件は、ここでは非常にうまくいく可能性があります。クライアントが制御を強制するのではなく、クライアントが非同期で購読する必要があると私は考えています。 –

0
  1. 号EndInvokeをのみが必要とされます。これをチェックしてください:threadまた、私はこれを投稿しましたthreadは半関連です。

  2. 私は本当にそのことであなたを助けません! :-) ごめんなさい。

+0

残念ながら、MSDNスレッドは確定的なものではありませんが、これを追跡できるポインタがいくつかあります。 –

1

これについてしばらく考えてから、Windowsフォームコントロールで非同期イベントを実行することはおそらく悪い考えです。 Windowsフォームのイベントは、UIスレッドで発生させる必要があります。そうしないと、クライアントに負担がかかり、AsyncResultオブジェクトと非同期例外が混乱する可能性があります。

クライアントが(BackgroundWorkerなどの技術を使用して)独自の非同期処理を起動したり、イベントを同期して処理できるようにすると、よりクリーンです。

もちろん、例外はあります。たとえば、System.Timers.Timerは、スレッドプールスレッドでElapsedイベントを発生させます。しかし、最初の通知はプールスレッド上で行われます。一般的なルールのように見える:最初の通知を持っている同じスレッド上のイベントを発生させる。少なくとも、それは私のために最も効果的なルールです。そうすれば、漏れた物については疑問はありません。

関連する問題