6

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 を持つ async-Method です。

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!

問題は、「await Task.Delay(500);」の場合です。ステートメントが実行されると、「receiver.Post(5).Wait();」もう待ちません。

いくつかのバリアント (TaskCompletionSource、ContinueWith など) を試しましたが、機能しません。

問題を解決する方法を知っている人はいますか?

4

1 に答える 1

4

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);
  }
}
于 2012-12-04T13:50:53.903 に答える