Как правильно обработать OperationCanceledException при отмене операции?

Я запускаю в отдельном потоке выполняться метод, в процессе выполнения которого возникает ситуация, когда нужно дождаться освобождения ресурса. В этом случае я запускаю ожидание через Task.Delay(Timeout.Infinite, source.Token), который потом прервется из другого потока, но у меня возникла проблема. После того как другой поток прерывает ожидание, он застревает в бесконечном цикле метода, вместо того чтоб разблокировать поток и продолжить выполнение.

using System;
using System.Threading;
using System.Threading.Tasks;

namespace DelayInfinite
{
    class Program
    {
        private static CancellationTokenSource source;

        static void Main(string[] args)
        {
            Task.Run(Work);

            Console.ReadKey();
            source.Cancel();

            Console.WriteLine("Press AnyKey to end");
            Console.ReadKey();
        }

        public static async void Work()
        {
            try
            {
                Console.WriteLine("Task.Delay(Infinite)");
                source = new CancellationTokenSource();
                await Task.Delay(Timeout.Infinite, source.Token);
            }
            catch
            {
                // ignored
            }

            Console.WriteLine("WhileTrue");
            while (true)
            {
                
            }
        }
    }
}

На данный момент я нашел два способа добиться того что я хочу:

  1. В обработке исключения добавить await Task.Delay(1); - в этом случае прерывающий поток обрабатывает ошибку и продолжает свою работу, а заблокированный поток возобновляет свою работу.
  2. При прерывании ожидания создавать новый поток Task.Run(() => source.Cancel()); - в этом случае создается новый поток, который продолжает выполнение метода в отдельном потоке.

У меня возник вопрос, как правильно обработать эту ситуацию? Есть ли другие способы возобновить работу потока? Текущие способы похожи на костыли, поэтому я ищу другие способы решить эту проблему.

UPD: Сделал еще один пример
Надеюсь по нему будет понятнее что я делаю.
При выполнении этого кода в консоль не выводится "End Work", потому что основной поток застревает в методе WorkAsync после отмены ожидания.

    class Program
    {
        private static CancellationTokenSource WaitResourceTokenSource;
        private static bool IsResourceAvailable = true;

        static async Task Main(string[] args)
        {
            var workTask = Task.Run(WorkAsync);

            await Task.Delay(10);
            IsResourceAvailable = false;

            await Task.Delay(100);
            IsResourceAvailable = true;
            WaitResourceTokenSource.Cancel();

            Console.WriteLine("End Work");
        }

        public static async Task WorkAsync()
        {
            Console.WriteLine("Begin Work");
            while (true)
            {
                if (!IsResourceAvailable)
                    await WaitResource();

                for (var i = 0; i < 5; i++)
                {
                    Method();
                }
            }
        }

        private static async Task WaitResource()
        {
            Console.WriteLine("Wait");
            try
            {
                WaitResourceTokenSource = new CancellationTokenSource();
                await Task.Delay(Timeout.Infinite, WaitResourceTokenSource.Token);
            }
            catch
            {
                // ignored
            }
            Console.WriteLine("End Wait");
        }

        private static void Method()
        {
            var sum = 0;
            for (var i = 0; i < 1000000; i++)
            {
                sum++;
            }
        }
    }

Ответы (0 шт):