私は、GUIによる簡単な消費を提供するために、オブジェクトメソッドから戻ることを選択しましTask<T>
た。Task
一部のメソッドは、他の種類のウェイトハンドルのミューテックスを単に待機します。そのために1つのトレッドプールスレッドをブロックする必要がないように、Task
から構築する方法はありますか?WaitHandle.Wait()
質問する
4810 次
2 に答える
18
これを行う方法があります。ThreadPool.RegisterWaitForSingleObjectメソッドを使用してWaitHandleにサブスクライブし、 TaskCompletionSourceクラスを介してラップすることができます。
public static class WaitHandleEx
{
public static Task ToTask(this WaitHandle waitHandle)
{
var tcs = new TaskCompletionSource<object>();
// Registering callback to wait till WaitHandle changes its state
ThreadPool.RegisterWaitForSingleObject(
waitObject: waitHandle,
callBack:(o, timeout) => { tcs.SetResult(null); },
state: null,
timeout: TimeSpan.MaxValue,
executeOnlyOnce: true);
return tcs.Task;
}
}
使用法:
WaitHandle wh = new AutoResetEvent(true);
var task = wh.ToTask();
task.Wait();
于 2012-12-06T11:13:35.903 に答える
11
Sergey Teplyakovの受け入れられた回答のコメントで@gordyが指摘しているように、MSDNは、登録されたWaitHandleのサブスクリプションを解除した実装を提案します。
コールバックの結果をサポートするために、ここで少し変更しました。登録がタイムアウトした場合、タスクはfalseを返します。シグナルが受信された場合、タスクはtrueを返します。
public static class ExtensionMethods
{
public static Task<bool> WaitOneAsync(this WaitHandle waitHandle, int timeoutMs)
{
if (waitHandle == null)
throw new ArgumentNullException(nameof(waitHandle));
var tcs = new TaskCompletionSource<bool>();
RegisteredWaitHandle registeredWaitHandle = ThreadPool.RegisterWaitForSingleObject(
waitHandle,
callBack: (state, timedOut) => { tcs.TrySetResult(!timedOut); },
state: null,
millisecondsTimeOutInterval: timeoutMs,
executeOnlyOnce: true);
return tcs.Task.ContinueWith((antecedent) =>
{
registeredWaitHandle.Unregister(waitObject: null);
try
{
return antecedent.Result;
}
catch
{
return false;
}
});
}
}
使用法は元の答えと同じです:
WaitHandle signal = new AutoResetEvent(initialState: false);
bool signaled = await signal.WaitOneAsync(1000);
if (signaled)
{
Console.WriteLine("Signal received");
}
else
{
Console.WriteLine("Waiting signal timed out");
}
于 2018-03-22T12:34:55.573 に答える