C# 在另一个线程中计时方法执行,并在超时时中止

C# 在另一个线程中计时方法执行,并在超时时中止,c#,multithreading,task-parallel-library,C#,Multithreading,Task Parallel Library,嗨,我正在尝试运行一个异步方法,以便对持续时间计时,并在超过超时时取消该方法 我试着用async和Wait来实现这一点。但是没有运气。也许我在这方面做得太过火了,任何意见都将受到赞赏 需要注意的是,我无法更改接口“TheirInterface”(因此得名) 迄今为止的代码: using System; using System.Diagnostics; public interface TheirInterface { void DoHeavyWork(); } public cla

嗨,我正在尝试运行一个异步方法,以便对持续时间计时,并在超过超时时取消该方法

我试着用async和Wait来实现这一点。但是没有运气。也许我在这方面做得太过火了,任何意见都将受到赞赏

需要注意的是,我无法更改接口“TheirInterface”(因此得名)

迄今为止的代码:

using System;
using System.Diagnostics;

public interface TheirInterface
{
    void DoHeavyWork();
}

public class Result
{
    public TimeSpan Elapsed { get; set; }
    public Exception Exception { get; set; }

    public Result(TimeSpan elapsed, Exception exception)
    {
        Elapsed = elapsed;
        Exception = exception;
    }
}

public class TaskTest
{
    public void Start(TheirInterface impl)
    {
        int timeout = 10000;

        // TODO
        // Run HeavyWorkTimer(impl)
        // 
        // Wait for timeout, will be > 0
        // 
        // if timeout occurs abortheavy
    }

    public Result HeavyWorkTimer(TheirInterface impl)
    {
        var watch = new Stopwatch();

        try
        {
            watch.Start();
            impl.DoHeavyWork();
            watch.Stop();
        }
        catch (Exception ex)
        {
            watch.Stop();

            return new Result(watch.Elapsed, ex);
        }

        return new Result(watch.Elapsed, null);
    }
}

您想创建一个计时器,当它过期时,将取消线程。如果没有合作取消,您将不得不调用
线程.Abort
,这不太理想。我假设您知道中止线程所涉及的危险

public Result HeavyWorkTimer(TheirInterface impl)
{
    var watch = new Stopwatch();
    Exception savedException = null;

    var workerThread = new Thread(() => 
    {
        try
        {
            watch.Start();
            impl.DoHeavyWork();
            watch.Stop();
        }
        catch (Exception ex)
        {
            watch.Stop();
            savedException = ex;
        }
    });

    // Create a timer to kill the worker thread after 5 seconds.
    var timeoutTimer = new System.Threading.Timer((s) =>
        {
            workerThread.Abort();
        }, null, TimeSpan.FromSeconds(5), TimeSpan.Infinite);

    workerThread.Start();

    workerThread.Join();

    return new Result(watch.Elapsed, savedException);
}
请注意,如果中止线程,线程将获得
ThreadAbortException


如果您能说服接口所有者添加合作取消,然后,您可以更改计时器回调,使其请求取消令牌,而不是调用
线程。Abort

您可能应该通过要求
取消令牌
作为
接口.DoHeavyWork
中的参数来强制执行协同取消,并将其转到
任务
。。。否则,据我所知,没有干净的方法“中止”在同一进程中运行的其他操作。@PatrykĆwiek很好的调用,我将向接口所有者建议。@PatrykĆwiek有最好的解决方案。你的其他选择是:启动一个专用线程并在超时时中止它(这会破坏应用程序域的稳定性);启动一个专用的应用程序域,并在超时时卸载它(这可能会破坏进程的稳定性);启动一个单独的进程,并在超时时终止它(这是中止不可取消代码的唯一真正安全的方法)。@StephenCleary我不同意这是解决方案。它没有解决超时要求,它只解决了优雅的中止-所以从我的角度来看,这个问题仍然存在stands@LarsNielsen好的,如果接口接受
CancellationToken
并异步工作,您可以取消一个。感谢您的输入,不幸的是接口所有者不想支持取消。我不敢中断这条线索,因为我不知道后果如何。因此,我没有调用workerThread.Abort(),而是决定引发一个事件,发出超时信号并通知用户。