0

I have the following test code to simulate the use of a semaphore and throttling task execution. Is there a way to not continue to create new tasks if one of the running tasks throws an exception like the below. I don't need the existing tasks to stop running, I just want no new tasks to start after the exception is encountered.

Currently the tasks will all start in this scenario below. I want it to stop after a few tasks are ran because of the exceptions being thrown.

            var testStrings = new List<string>();
            for (var i = 0; i < 5000; i++)
            {
                testStrings.Add($"string-{i}");
            }

            using (var semaphore = new SemaphoreSlim(10))
            {
                var tasks = testStrings.Select(async testString =>
                {
                    await semaphore.WaitAsync();
                    try
                    {
                        Console.WriteLine($"{testString}-Start");
                        await Task.Delay(2000);
                        throw new Exception("test");
                    }
                    finally
                    {
                        semaphore.Release();
                    }
                });

                await Task.WhenAll(tasks);
            }
mameesh
  • 3,651
  • 9
  • 37
  • 47
  • The naive approach is to set flag on error and return from any task (even during execution if you want) if flag become set. This has overhead of still having to start all the tasks. – Sinatr Oct 11 '17 at 13:32
  • 1
    Possible duplicate of [How to cancel and raise an exception on Task.WhenAll if any exception is raised?](https://stackoverflow.com/questions/41899842/how-to-cancel-and-raise-an-exception-on-task-whenall-if-any-exception-is-raised) – Sinatr Oct 11 '17 at 13:34
  • I think if I add a catch block to my try and say if (!cancellationTokenSource.IsCancellationRequested) cancellationTokenSource.Cancel(); and then wrap each in a if (!cancellationToken.IsCancellationRequested) that may work – mameesh Oct 11 '17 at 13:40

1 Answers1

1

As per Sinatr's comments, I think this may work for me by adding a cancellation token to be monitored.

       var testStrings = new List<string>();
        for (var i = 0; i < 5000; i++)
        {
            testStrings.Add($"string-{i}");
        }

        var cancellationTokenSource = new CancellationTokenSource();
        var cancellationToken = cancellationTokenSource.Token;

        using (var semaphore = new SemaphoreSlim(10))
        {
            var tasks = testStrings.Select(async testString =>
            {
                    await semaphore.WaitAsync();
                    try
                    {
                       if (!cancellationToken.IsCancellationRequested)
                       {
                           Console.WriteLine($"{testString}-Start");
                           await Task.Delay(2000);
                           throw new Exception("test");
                       }
                    }
                    catch (Exception ex)
                    {
                        if (!cancellationTokenSource.IsCancellationRequested)
                            cancellationTokenSource.Cancel();
                        throw;
                    }
                    finally
                    {
                        semaphore.Release();
                    }
            });

            await Task.WhenAll(tasks);
        }
mameesh
  • 3,651
  • 9
  • 37
  • 47