ActionBlockを持つクラスReceiverがあります。
public class Receiver<T> : IReceiver<T>
{
private ActionBlock<T> _receiver;
public Task<bool> Send(T item)
{
if(_receiver!=null)
return _receiver.SendAsync(item);
//Do some other stuff her
}
public void Register (Func<T, Task> receiver)
{
_receiver = new ActionBlock<T> (receiver);
}
//...
}
ActionBlockのRegister-Actionは、await-Statementを持つ非同期メソッドです。
private static async Task Writer(int num)
{
Console.WriteLine("start " + num);
await Task.Delay(500);
Console.WriteLine("end " + num);
}
今私がやりたいことは、排他的な振る舞いを得るためにアクションメソッドが終了するまで(条件が設定されている場合)同期的に待つことです。
var receiver = new Receiver<int>();
receiver.Register((Func<int, Task) Writer);
receiver.Send(5).Wait(); //does not wait the action-await here!
問題は「Task.Delay(500)を待っているとき」です。ステートメントが実行され、 "receiver.Post(5).Wait();"もう待つことはありません。
いくつかの変種(TaskCompletionSource、ContinueWith、...)を試してみましたが、うまくいきません。
誰かが問題を解決するためのアイデアを持っていますか?
ActionBlock
デフォルトでは排他的な振る舞いを強制します(一度に1つの項目だけが処理されます)。あなたが「排他的な振る舞い」によって何か他のことを意味するならば、あなたは使うことができますTaskCompletionSource
アクションが完了したときに送信者に通知するには
... use ActionBlock<Tuple<int, TaskCompletionSource<object>>> and Receiver<Tuple<int, TaskCompletionSource<object>>>
var receiver = new Receiver<Tuple<int, TaskCompletionSource<object>>>();
receiver.Register((Func<Tuple<int, TaskCompletionSource<object>>, Task) Writer);
var tcs = new TaskCompletionSource<object>();
receiver.Send(Tuple.Create(5, tcs));
tcs.Task.Wait(); // if you must
private static async Task Writer(int num, TaskCompletionSource<object> tcs)
{
Console.WriteLine("start " + num);
await Task.Delay(500);
Console.WriteLine("end " + num);
tcs.SetResult(null);
}
代わりに、あなたは使用することができますAsyncLock
(私のAsyncExライブラリに含まれています):
private static AsyncLock mutex = new AsyncLock();
private static async Task Writer(int num)
{
using (await mutex.LockAsync())
{
Console.WriteLine("start " + num);
await Task.Delay(500);
Console.WriteLine("end " + num);
}
}
AsyncLock
。コードサンプルについては、最新の回答を参照してください。アイテムがいつ処理されたかはもうわかりませんが、各アイテムは一度に1つずつ処理されます(以下を含む)。async
処理)。 - Stephen Cleary
_receiver
にTransformBlock
そして次の行動を新しいActionBlock
、 にリンク_receiver
? - svick