How do I wrap a rogue function with a timeout?

旧街凉风 提交于 2019-12-24 03:14:11

问题


I've got a function in a 3rd party library that occasionally goes rogue and never returns. Something like so:

    // 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);
        }
    }

I'd like to wrap it in a task with a timeout which is easy enough to do with a 'task.Wait(mills)'. While this returns control to me after the timeout, it doesn't actually kill the task.

In the code below, the rogue function continues to log after the timeout.

    [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).
        }
    }

How do I completely kill this task, so that I can retry it without ending up with a bunch of them running infinitely on my background thread pool.


回答1:


It seems that Thread.Abort is your only option. If you are afraid that doing so may leave the application in a corrupted state (open file handles etc), then the safest option is to run the thread in a different process, and then kill the process. Another workable solution is to run the thread in a different AppDomain, and then abort the thread and unload the AppDomain.




回答2:


UPDATED:

Let one has such a function:

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);
        }
    }
}

Possible solution is to wrap it with a class like this:

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;
        }
    }
}

Now one can start an infinite action like InfiniteAction.Start() and stop it like InfiniteAction.Stop().

It could be done manually:

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();
}

Or by timer:

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)}");
}


来源:https://stackoverflow.com/questions/55885426/how-do-i-wrap-a-rogue-function-with-a-timeout

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!