我目前正在为现有应用程序编写基于 Web 服务的前端。为此,我使用了WCF LOB 适配器 SDK,它允许创建自定义 WCF 绑定,将外部数据和操作公开为 Web 服务。
SDK 提供了一些接口来实现,并且它们的一些方法是有时间限制的:实现预期在指定的时间跨度内完成其工作或抛出TimeoutException。
调查使我想到了“实现 C# 通用超时”这个问题,它明智地建议使用工作线程。有了这些知识,我可以写:
public MetadataRetrievalNode[] Browse(string nodeId, int childStartIndex,
int maxChildNodes, TimeSpan timeout)
{
Func<MetadataRetrievalNode[]> work = () => {
// Return computed metadata...
};
IAsyncResult result = work.BeginInvoke(null, null);
if (result.AsyncWaitHandle.WaitOne(timeout)) {
return work.EndInvoke(result);
} else {
throw new TimeoutException();
}
}
但是,对于超时时如何处理工作线程的共识尚不清楚。可以像上面的代码一样忘记它,或者可以中止它:
public MetadataRetrievalNode[] Browse(string nodeId, int childStartIndex,
int maxChildNodes, TimeSpan timeout)
{
Thread workerThread = null;
Func<MetadataRetrievalNode[]> work = () => {
workerThread = Thread.CurrentThread;
// Return computed metadata...
};
IAsyncResult result = work.BeginInvoke(null, null);
if (result.AsyncWaitHandle.WaitOne(timeout)) {
return work.EndInvoke(result);
} else {
workerThread.Abort();
throw new TimeoutException();
}
}
现在,中止线程被广泛认为是错误的。它会破坏正在进行的工作、泄漏资源、混淆锁定,甚至不能保证线程实际上会停止运行。也就是说,HttpResponse.Redirect()
每次调用它都会中止一个线程,而 IIS 似乎对此非常满意。也许它已经准备好以某种方式处理它。我的外部应用程序可能不是。
另一方面,如果我让工作线程运行,除了资源争用增加(池中可用线程减少)之外,内存不会泄漏,因为work.EndInvoke()
永远不会被调用?MetadataRetrievalNode[]
更具体地说,返回的数组不会work
永远存在吗?
这只是选择两个弊端中较小的一个问题,还是有办法不中止工作线程并仍然回收所使用的内存BeginInvoke()
?