C# 调用一个方法并取消它,如果花费的时间太长,则返回调用方法

C# 调用一个方法并取消它,如果花费的时间太长,则返回调用方法,c#,.net-4.5.2,C#,.net 4.5.2,在c#中是否有一种方法可以调用一个方法,以便在该方法需要很长时间才能完成时,该方法将被取消并返回到调用方法?我想我可以用线程来实现这一点,但如果不需要线程呢 作为参考,我可能需要终止/停止/中止的方法是调用CorelDraw 15 API。这将打开CorelDraw的一个实例,我在此方法中收到了不可重复的错误。也就是说,我可以处理同一个图像两次,一次会冻结或出错,另一次不会 我目前使用的解决方案是让第二个应用程序执行处理.Start(firstAppExecutablePath),然后检查文本文

在c#中是否有一种方法可以调用一个方法,以便在该方法需要很长时间才能完成时,该方法将被取消并返回到调用方法?我想我可以用线程来实现这一点,但如果不需要线程呢

作为参考,我可能需要终止/停止/中止的方法是调用CorelDraw 15 API。这将打开CorelDraw的一个实例,我在此方法中收到了不可重复的错误。也就是说,我可以处理同一个图像两次,一次会冻结或出错,另一次不会


我目前使用的解决方案是让第二个应用程序执行
处理.Start(firstAppExecutablePath)
,然后检查文本文件中的变量,如果变量在10分钟后没有更改,
.Kill()。如果可能的话,我宁愿避免使用这种解决方案,因为它看起来很笨重,而且容易出现问题。因为它运行
.Kill()关闭的方式非常混乱,但通常不会引起问题。

线程是绝对需要的,除非您可以从函数中检查超时-您可能不同意。因此,这里有一个线程的简约方法:

private static bool ExecuteWithTimeout(TimeSpan timeout, Action action)
{
    Thread x = new Thread(() => { action(); });
    x.Start();

    if (!x.Join(timeout))
    {
        x.Abort(); //Or Interrupt instead, if you use e.g. Thread.Sleep in your method
        return false;
    }

    return true;
}

不内置,不,因为中断任意代码不能安全地完成(如果它在调用C库函数的中间(不支持异常),它只使用全局锁,需要释放它) 但是你可以自己写这样的支持。除非绝对必要,否则我不会在混合中添加线程,因为它们带来了潜在问题的全新维度

例如:

void Caller()
{
    int result;
    if (TryDoSomething(out result, 100)) {
        System.Console.WriteLine("Result: {0}", result);
    }
}

bool TryDoSomething(out int result, int timeoutMillis)
{
    var sw = Stopwatch.StartNew();
    result = 0x12345678;
    for (int i = 0; i != 100000000; ++i) {
        if (sw.ElapsedMilliseconds > timeoutMillis)
            return false;
        result += i / (result % 43) + (i % 19);
    }
    return true;
}

如果它不是线程化的,则无法检查超时,因为执行线程正在执行您的方法。无需检查“是否花费了太长时间?”您的api是否异步?这就是CancellationToken的用途。该方法在做什么?@BenHoffman我不清楚为什么这意味着你不能使用线程。正如您在对其中一个答案的注释中描述了运行第二个程序以杀死它一样,您可以运行另一个线程来杀死它。差别不大。因为它可能是一个非托管API,我不相信他的答案对您有效。不建议中止其他线程。如果另一个线程当前正在执行静态构造函数,则可能永远无法在该进程中使用该构造函数构造该类型的对象。请参阅中的说明。@Cameron
x.Abort()
没有“取消”它,线程“愉快地继续做它的事情”?我觉得很难相信…@LasseV.Karlsen是的,那太糟糕了。这就是为什么(如果我们知道代码OP的亲属正在尝试取消)任何带有CancellationToken或至少带有中断而不是中止的内容都会更可取的原因。啊,对不起,我没有看到
中止
。问题是
中止
不会在线程执行非托管代码时终止线程(这个API几乎肯定是这样的). 因此,它可能不会起作用<代码>中止
将等待非托管代码完成并且线程正在执行托管代码。这似乎并不能真正回答问题。OP需要一个方法调用来超时,而您所做的是在一段时间内重复一个简单的操作。在我看来不一样(尽管OP可能会有所不同)。@克里斯同意。您假设可以修改该方法以检查它已运行了多长时间。如果我试图使一个仅阻塞的IO操作超时,该怎么办?
TryDoSomething
是一个方法;-)大多数方法都可以在战略位置检测超时。循环只是一个例子。是的,这假设了对目标方法的控制,这已经被证明不是OP的情况。我将把答案留给一般情况。I/O和其他操作系统级别的操作往往具有非阻塞版本,可以通过足够的努力与超时集成。@Cameron我实际上无法在战略点检查超时。我调用的方法使用CorelDraw API打开CorelDraw并修改图形。问题最终是CorelDraw的API有缺陷,并不总是做同样的事情。我在一天内处理了数百个图形,每隔几百个图形就会发生奇怪的事情,CorelDraw会冻结或被一个复制函数卡住。现在,第二个应用程序在第一个应用程序运行太长时会杀死它,并且当它重新运行导致问题的同一个映像时,不会出现问题。@Ben:Hmm,这很烦人。我记得很久以前使用过CorelDraw,当时它也偶尔崩溃。我的回答显然不适用于你的情况,请忽略它!