Я запускаю в отдельном потоке выполняться метод, в процессе выполнения которого возникает ситуация, когда нужно дождаться освобождения ресурса. В этом случае я запускаю ожидание через 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)
{
}
}
}
}
На данный момент я нашел два способа добиться того что я хочу:
- В обработке исключения добавить
await Task.Delay(1);- в этом случае прерывающий поток обрабатывает ошибку и продолжает свою работу, а заблокированный поток возобновляет свою работу. - При прерывании ожидания создавать новый поток
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++;
}
}
}
Текущие способы похожи на костыли>async void... – EvgeniyZ Mar 14 '21 at 17:04await Task.Delay(1);. – Анатолий Гладких Mar 22 '21 at 05:46Console.KeyAvailableвам не походит? – aepot Mar 22 '21 at 06:40Method()досчитает до конца, что бы вы не делали. А следовательно смысла 0 во всем этом. Представьте, чтоMethod()работает 10 секунд. Засуньте туда паузы, выведите конечную сумму в консоль в конце концов. Что отменять то собрались? Вопрос же про отмену был? Создайте рабочий пример сначала, типа того что я вам написал, но на этот раз сами. Попробуйте реально отменить что-то, а не фейково. – aepot Mar 22 '21 at 06:51CancellationTokenSource-IDisposableи содержит неуправляемые ресурсы: Использование объектов, реализующих IDisposable – aepot Mar 22 '21 at 06:59await Task.Delay(Timeout.Infinite, WaitResourceTokenSource.Token);, а метод WorkAsync должен продолжить свою работу. Проблема в том что поток, который прерывает ожидание, застревает в методе WorkAsync, а мне необходимо чтоб он разблокировал спящий поток, после чего продолжил бы выполнение. – Анатолий Гладких Mar 23 '21 at 09:20