DoTheStuff().Wait();
コンソール アプリケーションとして実行している場合、次のプログラムがハングします。
namespace Test
{
using System.Threading.Tasks;
using System.Windows.Forms;
class Program
{
static void Main(string[] args)
{
new Form();
DoTheStuff().Wait();
}
private static async Task DoTheStuff()
{
await Task.Delay(1000);
}
}
}
ただし、行をコメントアウトすると、期待どおりに機能しますnew Form();
。(1 秒間実行してから終了します)。
期待される動作を維持しながら Form インスタンスを保持するにはどうすればよいですか?
さて、興味があれば背景をいくつか:
Windows サービスとして (ローカルでテストするときはコンソールとして) ホストされているアプリケーションがあります。
SystemEvents.TimeChanged
イベントにアクセスできる必要があります。
ただし、ドキュメントに従って、これは Windows フォームがある場合にのみ機能します (したがって、サービスまたはコンソール アプリでは機能しません)。回避策は、リンクされたドキュメントに記載されており、非表示のフォームを作成することで構成されています。
残念ながら、プログラムは代わりに完全にフリーズします。これは、await とForm
インスタンスを持つことの組み合わせが原因です。
SystemEvents.TimeChanged
では、イベントにアクセスしている間、どうすれば予想される非同期/待機動作を維持できますか?
以下のヘルプのおかげで、フリーズせずに動作する修正されたコードがここにあります。
namespace Test
{
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
class Program
{
static void Main(string[] args)
{
new Thread(() => Application.Run(new Form())).Start();
// SynchronizationContext.SetSynchronizationContext(null);
DoTheStuff().Wait();
}
private static async Task DoTheStuff()
{
await Task.Delay(1000);
}
}
}
私のプログラムでは、待機中のタスクにスレッドプールを使用する必要があるため、「SynchronizationContext.SetSynchronizationContext(null);」を使用する必要があります。フォームは明らかに何らかの理由で初期化したため、これは良い習慣ではないと思います。しかし、ユーザー入力なしで非表示のフォームを実行すると (これはサービスです!)、今のところ害は見られません。
MS は例 2 を使用して発生する可能性のある問題についても言及していないため、ドキュメントは少し不完全に感じられます (await/async は、フォームのインスタンス化時に動作を暗黙的に変更します)。