0

I have a code block which is eventually accessed by multiple threads. I search for an up to date async mechanism to continue executing when all threads have passed.

Currently I do the following with a CountDownEvent which works just fine (without async support).

    public class Watcher
{
    private static readonly Logger Log = LogManager.GetCurrentClassLogger();

    private readonly CountdownEvent _isUpdating = new CountdownEvent(1);
    private readonly IActivity _activity;

    public Watcher([NotNull] IActivity activity)
    {
        _activity = activity ?? throw new ArgumentNullException(nameof(activity));
        _activity.Received += OnReceived;
    }

    private void OnReceived(IReadOnlyCollection<Summary> summaries)
    {
        _isUpdating.AddCount();

        try
        {
            // Threads processing
        }
        finally
        {
            _isUpdating.Signal();
        }
    }

    private void Disable()
    {
        _activity.Received -= OnReceived;

        _isUpdating.Signal();

        /* await */ _isUpdating.Wait();
    }
}

Do I need to use any of those AsyncCountdownEvent implementations or is there any other built-in mechanism? I already thought about using a BufferBlock because it has async functionality but I think it's a bit overkill.

Additional to the comments:

IActivity is a WebService call (but shouldn't effect the implementation on top or vice versa)

        public async Task Start(bool alwayRetry = true, CancellationToken cancellationToken = new CancellationToken())
    {
        var milliseconds = ReloadSeconds * 1000;

        do
        {
            try
            {
                var summaries = await PublicAPI.GetSummariesAsync(cancellationToken).ConfigureAwait(false);
                OnSummariesReceived(summaries);
            }
            catch (Exception ex)
            {
                Log.Error(ex.Message);

                OnErrorOccurred(ex);
            }

            await Task.Delay(milliseconds, cancellationToken).ConfigureAwait(false);
            // ReSharper disable once LoopVariableIsNeverChangedInsideLoop
        } while (alwayRetry);
    }
BlackMatrix
  • 474
  • 5
  • 19
  • Have a look at Task.WhenAll https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.whenall?view=netframework-4.7.1#System_Threading_Tasks_Task_WhenAll_System_Threading_Tasks_Task___ – Marco Feb 21 '18 at 12:24
  • I do not really have the tasks references, just a code block which could be accessed by multiple threads. – BlackMatrix Feb 21 '18 at 13:13

1 Answers1

0

It's not clear the IActivity signatures; but you can wait for a range of tasks to be completed:

class MultiAsyncTest {

    Task SomeAsync1() { return Task.Delay(1000); }

    Task SomeAsync2() { return Task.Delay(2000);}

    Task EntryPointAsync() {
        var tasks = new List<Task>();
        tasks.Add(SomeAsync1());
        tasks.Add(SomeAsync2());
        return Task.WhenAll(tasks);
    }

}

What's IActivity's signature? Does it support Task? Or you are using Thread? More explanation would help to a more specified answer.

amiry jd
  • 27,021
  • 30
  • 116
  • 215
  • Edited the initial post. But it shouldn't matter how the implemention of IActivity is. I just want to get the process finished and CountdownEvent is already just fine without the async support. Sure I could wrap a Task.Run around but that's not the best solution I guess. – BlackMatrix Feb 21 '18 at 13:01
  • OK I get it. I thought you want to wait for `IActivity` executions (while I didn't ask for implementation, but for signature; no matter). But I think now you want to start and wait for some threads in `// Threads processing` part. Right? Whay not to start some `Task`s here and wait for them? – amiry jd Feb 21 '18 at 14:37