この問題について、さらに詳しい情報があります (私は mikecamimo と同じチームで働いています)。
この問題は、正しくレプリケートされると、Windows フォーム アプリケーションでも発生します。元のOPでは、ブロッキングがなかったため、Windowsフォームでは問題は発生しませんでした。ResetEvent を使用してブロッキングを導入すると、同じ問題が発生します。
これは、イベント ハンドラー (Widget_Completed) が Widget.DoWork を呼び出すメソッドと同じスレッド上にあるためです。AutoResetEvent.WaitOne(); の結果 イベントハンドラーがイベントを設定するために呼び出されることはないため、永久にブロックされます。
Windows フォーム環境では、Application.DoEvents を使用してメッセージ キューをポーリングし、イベントを処理できるようにすることで、これを回避できます。下記参照。
using System;
using System.Threading;
using System.Windows.Forms;
class Program
{
EventArgs data;
static void Main()
{
Program p = new Program();
p.RunWidget();
}
public Program()
{
_autoEvent = new AutoResetEvent(false);
}
public void RunWidget()
{
ThirdParty widget = new ThirdParty();
widget.Completed += new EventHandler(this.Widget_Completed);
data = null;
widget.DoWork();
while (data == null);
Application.DoEvents();
// do stuff with the results of DoWork that are contained in EventArgs.
}
// Assumes that some kind of args are passed by the event
public void Widget_Completed(object sender, EventArgs e)
{
data = e;
}
}
Windows サービスなどの非 Windows フォーム アプリケーションでは、アプリケーションが使用できないため、DoEvents を呼び出すことができません。
問題はスレッドの 1 つであり、widget.DoWork に関連付けられたイベント ハンドラーは何らかの方法で別のスレッドにある必要があります。これにより、AutoResetEvent.WaitOne が無期限にブロックされるのを防ぐことができます。おもう... :)
これを達成する方法についてのアイデアは素晴らしいでしょう。