我正在学习任务并行库(与C#5.0 async / await ),我想要做这样的事情:
public class Foo { public void UnblockDoSomething() { DoWork(); // notify DoSomethingAsync } public async Task DoSomethingAsync() { DoSomeWork(); await ... // Wait until UnblockDoSomething is called DoMoreWork(); } }在传统的线程模型中,我可以使用条件变量来完成此任务。 这个问题的TPL解决方案是什么?
I'm learning the Task Parallel Library (in conjunction with C# 5.0 async/await), and I want to do something like this:
public class Foo { public void UnblockDoSomething() { DoWork(); // notify DoSomethingAsync } public async Task DoSomethingAsync() { DoSomeWork(); await ... // Wait until UnblockDoSomething is called DoMoreWork(); } }In a traditional threaded model, I can accomplish this using condition variables. What is the TPL solution to this problem?
最满意答案
如果您只是一次一个通知,则可以使用TaskCompletionSource :
public class Foo { private TaskCompletionSource<object> _signal = new TaskCompletionSource<object>(); public void UnblockDoSomething() { DoWork(); _signal.SetResult(null); _signal = new TaskCompletionSource<object>(); } public async Task DoSomethingAsync() { var continueSignal = _signal.Task; DoSomeWork(); await continueSignal; DoMoreWork(); } }另一种选择是使用信号量( SemaphoreSlim ),它将“记住”以前是否已经发出信号:
public class Foo { private readonly SemaphoreSlim _mutex = new SemaphoreSlim(0); public void UnblockDoSomething() { DoWork(); _mutex.Release(); } public async Task DoSomethingAsync() { DoSomeWork(); await _mutex.WaitAsync(); DoMoreWork(); } }如果您确实需要一个条件变量,那么可以使用AsyncEx库中的 AsyncConditionVariable :
public class Foo { private readonly AsyncLock _mutex = new AsyncLock(); private readonly AsyncConditionVariable _cv = new AsyncConditionVariable(_mutex); public void UnblockDoSomething() { using (await _mutex.LockAsync()) { DoWork(); _cv.Notify(); } } public async Task DoSomethingAsync() { using (await _mutex.LockAsync()) { DoSomeWork(); await _cv.WaitAsync(); DoMoreWork(); } } }If you just have a one-at-a-time notification, you can use TaskCompletionSource:
public class Foo { private TaskCompletionSource<object> _signal = new TaskCompletionSource<object>(); public void UnblockDoSomething() { DoWork(); _signal.SetResult(null); _signal = new TaskCompletionSource<object>(); } public async Task DoSomethingAsync() { var continueSignal = _signal.Task; DoSomeWork(); await continueSignal; DoMoreWork(); } }Another option is to use a semaphore (SemaphoreSlim), which will "remember" if it's been signalled previously:
public class Foo { private readonly SemaphoreSlim _mutex = new SemaphoreSlim(0); public void UnblockDoSomething() { DoWork(); _mutex.Release(); } public async Task DoSomethingAsync() { DoSomeWork(); await _mutex.WaitAsync(); DoMoreWork(); } }If you truly need a condition variable, you can use AsyncConditionVariable from my AsyncEx library:
public class Foo { private readonly AsyncLock _mutex = new AsyncLock(); private readonly AsyncConditionVariable _cv = new AsyncConditionVariable(_mutex); public void UnblockDoSomething() { using (await _mutex.LockAsync()) { DoWork(); _cv.Notify(); } } public async Task DoSomethingAsync() { using (await _mutex.LockAsync()) { DoSomeWork(); await _cv.WaitAsync(); DoMoreWork(); } } }更多推荐
发布评论