2016-01-13 51 views
4

我目前正在使用一个使用来自不同部门的程序集的软件。
我把这个组件的方法是这样的:取消命令的执行时间太长

using (var connection = (IConnection) Factory.GetObject(typeof (IConnection))) 

使用完全正常工作的代码。但是在最后几分钟里,当我尝试启动它时,似乎我的程序没有做任何事情。在调试过程中按下暂停,表明它在上面的线上“卡住”了。
我的猜测是他们只是在做一些维护或某些事情,但这不是重点。
所以我虽然很高兴告诉用户如果程序无法启动,出了什么问题。简单的东西就像

MessageBox.Show("Could not connect", "Connection Error"); 

然后关闭程序。我的问题是:
如何在一段时间后终止命令的执行并跳到别的地方?
我的猜测是将它移动到一个单独的线程,然后让调用线程休眠几秒钟,之后它会处理额外的线程,如果它尚未完成。但是,这似乎真的对我来说很脏,这是一个更好的方法。

+0

如果你的'IConnection'是'SqlConnection',你可以使用它提供的默认连接超时。 – 2016-01-13 10:36:24

+0

@Kilanny虽然使用非常相似,但它不是SqlConnection,没有人似乎打扰实现超时。 – Wilsu

+0

否则使用'Timer'来检查执行,当超时时它应该终止作业 – 2016-01-13 10:44:02

回答

4

你的问题可以分成两个部分:

  1. 如何终止命令的执行?

唯一的方法是中止线程。 但是不要这样做。没有保证和安全的方式。有像Thread.Interrupt和Thread.Abort这样的方法可以唤醒线程。但是,只有当线程处于WaitSleepJoin状态并且挂起在托管代码中时,它们才会工作。

看起来像你已经知道它。但是再一次,如果程序集中的东西无限地挂起了代码的执行,那么线程可能“不见了”。所以你说得对,该程序应该关闭。

  1. ...跳到其他地方?

好的方法是使用TPL和异步模型。 下面是一个扩展方法来包装任何任务并在超时后到期。

public static async Task TimeoutAfter(this Task task, int millisecondsTimeout) 
{ 
    if (task == await Task.WhenAny(task, Task.Delay(millisecondsTimeout))) 
     await task; 
    else 
     throw new TimeoutException(); 
} 

然后用它

try 
{ 
    using (var result = await Task.Run(() => (IConnection)Factory.GetObject(typeof(IConnection))).TimeoutAfter(1000)) 
    { 
     ... 
    } 
} 
catch (TimeoutException ex) 
{ 
    //timeout 
} 

Here你可以找到更多的信息,这样做没有额外的库或扩展方法的

+0

详细的答案给予更详细的说明。我喜欢它。谢谢。 – Wilsu

2

如上所述,如果未实现本机超时,则最简单的方法是单独加载一个线程。虽然这听起来像它会非常脏,这是因为(使用Rx)的简单:

Task<IConnection> connectionTask = Observable.Start(() => Factory.GetObject(typeof (IConnection)), Scheduler.Default).Timeout(TimeSpan.FromSeconds(20)).ToTask()); 
using (var connection = connectionTask.Result) 
{ 
    ... 
} 

你可以调整Scheduler,如果你不希望它的线程池运行。如果Factory.GetObject的呼叫时间超过20秒,它将抛出一个TimeoutException

+0

同样的想法,但很多顺畅。非常感谢。我用'try-catch'包围它,但是当我尝试调试时,它说它永远不会达到我放在catch中的断点。看起来很奇怪,我明天再看看这个。 – Wilsu

3

一个简单的方法:

using (var task = new Task<IConnection>(() => Factory.GetObject(typeof(IConnection)))) 
{ 
    task.Start(); 

    if(!task.Wait(timeoutMilliseconds)) 
    { 
     throw new TimeoutException(); 
    } 

    IConnection result = task.Result; 
} 

Task.Wait做什么你想要的,因为如果它可以抛出异常原来假(任务没有及时完成。)

,如果你有一个动作不返回的东西这是更简单:

if (!Task.Run(action).Wait(timeoutMilliseconds)) 
{ 
    throw new TimeoutException(); 
} 

哪里action一些Action或λ。