我们有一个Windows服务调用第三方方法,当最终用户不正确配置时,该方法可能会挂起,这很难事先测试。我们通过在具有超时的任务中调用方法来处理这种风险:
private int? FooWithTimeout()
{
var timeout = TimeSpan.FromMinutes(1);
var task = Task.Run(Foo);
if (!task.Wait(timeout))
{
Log("Foo timed out...");
return null;
}
if (task.IsFaulted)
{
Log("Foo threw an exception...");
return null;
}
return task.Result;
}
第三方方法永远阻止等待来自无法响应的资源的输入。 不支持以任何方式,形状或形式取消,也没有内置超时。我们担心的是,随着服务运行,这些任务将继续阻塞并慢慢积累,最终消耗大量资源。
这是一个有效的问题吗?我们需要以某种方式中止/处理任务吗?如果是这样,这样做的正确方法是什么?
附录:有问题的第三方是Crystal Reports。当要求打印到需要用户提供某种额外输入的打印机时,它会挂起(例如,如果您打印文件,Microsoft XPS Document Writer会提示您保存文件的位置)。挂起,我的意思是它试图显示用户提示以获取额外的输入,但它在Windows服务中,所以没有人看到用户提示,它等待人类永远告诉它如何打印。我们允许最终用户配置服务尝试打印到哪台打印机,并且没有任何方法可以判断给定打印机是否需要额外的输入,而不是尝试打印到它。
答案 0 :(得分:3)
我们担心的是,当服务运行时,这些任务将继续阻塞并慢慢积累
这是一个有效的问题。您可以通过在使用小堆栈的特殊线程池上启动这些任务来减少其后果。这样就减少了内存使用量。但它不是一个完整的解决方案。如果你的应用程序必须运行很长时间(不是用于几个小时的GUI应用程序),那么这个解决方案将被证明是不可接受的,因为最终应用程序将遭受资源耗尽。
.NET无法终止不合作的线程。您需要在自己的进程中运行这些操作。然后,您可以安全地终止这些过程。
使用AppDomains也可能是安全的,但不太确定。当AppDomain和其中的线程中止时,每个进程状态可能会被破坏。此外,并非所有线程都可以中止。特别是IO操作。
使用单独的进程也不能保证终止时不会导致状态损坏。但在实践中,大多数腐败状态都存在于记忆中。进程终止可能会清除所有不一致的状态。
答案 1 :(得分:0)
一种方法可能是创建单独的线程来监视任何新创建的窗口 - 如果创建了任何新窗口 - 线程会尝试强制关闭它们。
枚举窗口:
How to enumerate all windows belonging to a particular process using .NET?
关闭非想要的窗口:
可能不起作用,只是提案......: - )