リソースを消費するライブラリを作成していますが、何らかの理由で API が異なるスレッドでイベントが発生するように設計されていますが、API の呼び出しはメイン スレッドで行う必要があります。
私が消費しようとしている API が次のように定義されているとしましょう (イベント定義は省略します)。
public sealed class DodgyService
{
public void MethodThatHasToBeCalledOnTheMainThread() { ... }
}
この API を使用するために、新しいタスクを作成する Service (そう、非常に元の名前) という名前のライブラリにサービスを追加しました ( SynchronizationContext
.
これが私の実装です:
public class Service
{
private readonly TaskFactory _taskFactory;
private readonly TaskScheduler _mainThreadScheduler;
public Service(TaskFactory taskFactory, TaskScheduler mainThreadScheduler)
{
_taskFactory = taskFactory;
_mainThreadScheduler = mainThreadScheduler;
}
// Assume this method can be called from any thread.
// In this sample is called by the main thread but most of the time
// the caller will be running on a background thread.
public Task ExecuteAsync(string taskName)
{
return _taskFactory.StartNew(
() => ReallyLongCallThatForWhateverStupidReasonHasToBeCalledOnMainThread(taskName),
new CancellationToken(false), TaskCreationOptions.None, _mainThreadScheduler)
.ContinueWith(task => Trace.TraceInformation("ExecuteAsync has completed on \"{0}\"...", taskName));
}
private void ReallyLongCallThatForWhateverStupidReasonHasToBeCalledOnMainThread(string taskName)
{
Trace.TraceInformation("Starting \"{0}\" really long call...", taskName);
new DodgyService().MethodThatHasToBeCalledOnTheMainThread();
Trace.TraceInformation("Finished \"{0}\" really long call...", taskName);
}
}
ここで、(メイン スレッドで) サービスの呼び出しを実行し、メイン スレッドで待機しようとすると、メイン スレッドで実行するようにスケジュールされたタスクをメイン スレッドが待機するため、アプリケーションはデッドロックに入ります。
プロセス全体をブロックせずにこれらの呼び出しをメイン スレッドにマーシャリングするにはどうすればよいですか?
ある時点で、新しいタスクを作成する前にメインスレッドの検出を実行することを考えましたが、これをハックしたくありません。
興味のある人のために、コードと問題を示す WPF アプリの要点をここで入手しました。
ちなみに、ライブラリは.net Framework 4.0で作成する必要があります
編集!ここに提供されているように、スコット・チェンバレンから提供されたアドバイスに従って問題を解決しました