Mih*_*tea 31 .net c# multithreading asynchronous task-parallel-library
什么是AutoResetEvent的异步(等待)等价物?
如果在经典线程同步中我们会使用这样的东西:
AutoResetEvent signal = new AutoResetEvent(false);
void Thread1Proc()
{
//do some stuff
//..
//..
signal.WaitOne(); //wait for an outer thread to signal we are good to continue
//do some more stuff
//..
//..
}
void Thread2Proc()
{
//do some stuff
//..
//..
signal.Set(); //signal the other thread it's good to go
//do some more stuff
//..
//..
}
Run Code Online (Sandbox Code Playgroud)
我希望以新的异步方式做事,这样的事情会变成:
SomeAsyncAutoResetEvent asyncSignal = new SomeAsyncAutoResetEvent();
async void Task1Proc()
{
//do some stuff
//..
//..
await asyncSignal.WaitOne(); //wait for an outer thread to signal we are good to continue
//do some more stuff
//..
//..
}
async void Task2Proc()
{
//do some stuff
//..
//..
asyncSignal.Set(); //signal the other thread it's good to go
//do some more stuff
//..
//..
}
Run Code Online (Sandbox Code Playgroud)
我已经看到了其他定制的解决方案,但是我在某个时间点设法得到了什么,仍然涉及锁定线程.我不希望这只是为了使用新的await语法.我正在寻找一个真正的等待信号机制,它不会锁定任何线程.
这是我在任务并行库中缺少的东西吗?
编辑:只是为了弄清楚:SomeAsyncAutoResetEvent是一个完全组成的类名,在我的例子中用作占位符.
Ste*_*ary 22
如果你想建立自己的,Stephen Toub有关于这个主题的权威博客文章.
如果你想使用已经写好的,我的AsyncEx库中有一个.AFAIK,截至撰写本文时,没有其他选择.
Dre*_*kes 14
这是Stephen Toub的来源AsyncAutoResetEvent,以防他的博客离线.
public class AsyncAutoResetEvent
{
private static readonly Task s_completed = Task.FromResult(true);
private readonly Queue<TaskCompletionSource<bool>> m_waits = new Queue<TaskCompletionSource<bool>>();
private bool m_signaled;
public Task WaitAsync()
{
lock (m_waits)
{
if (m_signaled)
{
m_signaled = false;
return s_completed;
}
else
{
var tcs = new TaskCompletionSource<bool>();
m_waits.Enqueue(tcs);
return tcs.Task;
}
}
}
public void Set()
{
TaskCompletionSource<bool> toRelease = null;
lock (m_waits)
{
if (m_waits.Count > 0)
toRelease = m_waits.Dequeue();
else if (!m_signaled)
m_signaled = true;
}
toRelease?.SetResult(true);
}
}
Run Code Online (Sandbox Code Playgroud)
这是我编写的一个版本,它允许您指定超时。它源自 Stephen Toub 的解决方案。我们目前在生产工作负载中使用它。
public class AsyncAutoResetEvent
{
readonly LinkedList<TaskCompletionSource<bool>> waiters =
new LinkedList<TaskCompletionSource<bool>>();
bool isSignaled;
public AsyncAutoResetEvent(bool signaled)
{
this.isSignaled = signaled;
}
public Task<bool> WaitAsync(TimeSpan timeout)
{
return this.WaitAsync(timeout, CancellationToken.None);
}
public async Task<bool> WaitAsync(TimeSpan timeout, CancellationToken cancellationToken)
{
TaskCompletionSource<bool> tcs;
lock (this.waiters)
{
if (this.isSignaled)
{
this.isSignaled = false;
return true;
}
else if (timeout == TimeSpan.Zero)
{
return this.isSignaled;
}
else
{
tcs = new TaskCompletionSource<bool>();
this.waiters.AddLast(tcs);
}
}
Task winner = await Task.WhenAny(tcs.Task, Task.Delay(timeout, cancellationToken));
if (winner == tcs.Task)
{
// The task was signaled.
return true;
}
else
{
// We timed-out; remove our reference to the task.
// This is an O(n) operation since waiters is a LinkedList<T>.
lock (this.waiters)
{
bool removed = this.waiters.Remove(tcs);
Debug.Assert(removed);
return false;
}
}
}
public void Set()
{
lock (this.waiters)
{
if (this.waiters.Count > 0)
{
// Signal the first task in the waiters list. This must be done on a new
// thread to avoid stack-dives and situations where we try to complete the
// same result multiple times.
TaskCompletionSource<bool> tcs = this.waiters.First.Value;
Task.Run(() => tcs.SetResult(true));
this.waiters.RemoveFirst();
}
else if (!this.isSignaled)
{
// No tasks are pending
this.isSignaled = true;
}
}
}
public override string ToString()
{
return $"Signaled: {this.isSignaled.ToString()}, Waiters: {this.waiters.Count.ToString()}";
}
}
Run Code Online (Sandbox Code Playgroud)
小智 7
我认为在MSDN上有很好的例子:https://msdn.microsoft.com/en-us/library/hh873178%28v=vs.110%29.aspx#WHToTap
public static Task WaitOneAsync(this WaitHandle waitHandle)
{
if (waitHandle == null)
throw new ArgumentNullException("waitHandle");
var tcs = new TaskCompletionSource<bool>();
var rwh = ThreadPool.RegisterWaitForSingleObject(waitHandle,
delegate { tcs.TrySetResult(true); }, null, -1, true);
var t = tcs.Task;
t.ContinueWith( (antecedent) => rwh.Unregister(null));
return t;
}
Run Code Online (Sandbox Code Playgroud)
我还在寻找 AsyncAutoResetEvent 类,现在似乎在命名空间 Microsoft.VisualStudio.Threading 中有一个可用的类
// Summary:
// An asynchronous implementation of an AutoResetEvent.
[DebuggerDisplay("Signaled: {signaled}")]
public class AsyncAutoResetEvent
Run Code Online (Sandbox Code Playgroud)