Как обернуть мошенническую функцию тайм-аутом?

У меня есть функция в сторонней библиотеке, которая иногда выходит из строя и никогда не возвращается. Как то так:

    // This is 3rd party function so I can't make it take a cancellation token.
    public void RogueFunction()
    {

        while (true)
        {
            _logger.LogInformation("sleeping...");
            Thread.Sleep(100);
        }
    }

Я хотел бы заключить его в задачу с тайм-аутом, который достаточно легко сделать с помощью "task.Wait (mills)". Хотя это возвращает мне контроль после тайм-аута, на самом деле это не убивает задачу.

В приведенном ниже коде мошенническая функция продолжает регистрироваться после истечения времени ожидания.

    [Fact]
    public void Test()
    {
        var task = Task.Factory.StartNew(RogueFunction);
        var complete = task.Wait(500);
        if (!complete)
        {
            // how do I kill the task so that it quits logging?
            Thread.Sleep(5000);

            task.Dispose();  // Throws exception: A task may only be disposed if it is in a completion state (RanToCompletion, Faulted or Canceled).
        }
    }

Как мне полностью убить эту задачу, чтобы я мог повторить ее, не заканчивая кучей из них, бесконечно работающих в моем фоновом пуле потоков.

2 ответа

Решение

Кажется, что Thread.Abort это ваш единственный вариант. Если вы боитесь, что это может привести к тому, что приложение будет повреждено (дескрипторы открытых файлов и т. Д.), Тогда самый безопасный вариант - запустить поток в другом процессе, а затем завершить процесс. Другое работоспособное решение - запустить поток в другом домене приложений, а затем прервать поток и выгрузить домен приложений.

ОБНОВЛЕНО:

Пусть у человека есть такая функция:

static class Rogue
{
    // This is 3rd party function so I can't make it take a cancellation token.
    public static void RogueFunction()
    {
        while (true)
        {
            Console.WriteLine("RogueFunction works");
            Thread.Sleep(1000);
        }
    }
}

Возможное решение состоит в том, чтобы обернуть это классом как это:

public class InfiniteAction
{
    private readonly Action action;
    private CancellationTokenSource cts;
    private Thread thread;

    public InfiniteAction(Action action) => this.action = action;

    public void Join() => thread?.Join();

    public void Start()
    {
        if (cts == null)
        {
            cts = new CancellationTokenSource();
            thread = new Thread(() => action());
            thread.IsBackground = true;
            thread.Start();
            cts.Token.Register(thread.Abort);
        }
    }

    public void Stop()
    {
        if (cts != null)
        {
            cts.Cancel();
            cts.Dispose();
            cts = null;
        }
    }
}

Теперь можно начать бесконечное действие, как InfiniteAction.Start() и остановить это как InfiniteAction.Stop(),

Это можно сделать вручную:

void ManualCancelation()
{
    var infiniteAction = new InfiniteAction(Rogue.RogueFunction);
    Console.WriteLine("RogueFunction is executing.");
    infiniteAction.Start();

    Console.WriteLine("Press any key to stop it.");
    Console.ReadKey();
    Console.WriteLine();
    infiniteAction.Stop();

    Console.WriteLine("Make sure it has stopped and press any key to exit.");
    Console.ReadKey();
    Console.WriteLine();
}

Или по таймеру:

void ByTimerCancelation()
{
    var interval = 3000;
    var infiniteAction = new InfiniteAction(Rogue.RogueFunction);
    Console.WriteLine($"RogueFunction is executing and will be stopped in {interval} ms.");
    Console.WriteLine("Make sure it has stopped and press any key to exit.");
    infiniteAction.Start();
    var timer = new Timer(StopInfiniteAction, infiniteAction, interval, -1);
    Console.ReadKey();
    Console.WriteLine();
}

private void StopInfiniteAction(object action)
{
    var infiniteAction = action as InfiniteAction;
    if (infiniteAction != null)
        infiniteAction.Stop();
    else
        throw new ArgumentException($"Invalid argument {nameof(action)}");
}
Другие вопросы по тегам