gpt4 book ai didi

c# - 在实现时间受限的方法时,我应该中止工作线程还是让其自行运行?

转载 作者:太空狗 更新时间:2023-10-30 00:45:55 25 4
gpt4 key购买 nike

我目前正在为现有应用程序编写基于 Web 服务的前端。为此,我使用了 WCF LOB Adapter SDK ,它允许创建自定义 WCF 绑定(bind),将外部数据和操作公开为 Web 服务。

SDK 提供了一些接口(interface)来实现,其中一些方法有时间限制:实现预计在指定的时间跨度内完成其工作或抛出 TimeoutException。 .

调查使我想到了“Implement C# Generic Timeout”这个问题,该问题明智地建议使用工作线程。有了这些知识,我可以写:

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() 永远不会被调用?更具体地说,work 返回的 MetadataRetrievalNode[] 数组不会永远保留吗?

这只是两害相权取其轻的问题,还是有办法不中止工作线程并仍然回收 BeginInvoke() 使用的内存?

最佳答案

嗯,先关Thread.Abort几乎没有以前那么糟糕了。 2.0 中对 CLR 进行了多项改进,修复了与中止线程相关的几个主要问题。请注意,它仍然很糟糕,所以避免它是最好的做法。如果您必须求助于中止线程,那么至少您应该考虑从中止起源的地方拆除应用程序域。在大多数情况下,这将具有令人难以置信的侵入性,并且无法解决非托管资源可能出现的损坏问题。

除此之外,在这种情况下中止还会产生其他影响。最重要的是您正试图中止 ThreadPool线。我真的不确定最终结果会是什么,它可能会有所不同,具体取决于所使用的框架版本。

最好的做法是让您的 Func<MetadataRetrievalNode[]>委托(delegate)在安全点轮询一个变量,看它是否应该自行终止执行。

public MetadataRetrievalNode[] Browse(string nodeId, int childStartIndex, int maxChildNodes, TimeSpan timeout)
{
bool terminate = false;

Func<MetadataRetrievalNode[]> work =
() =>
{
// Do some work.

Thread.MemoryBarrier(); // Ensure a fresh read of the terminate variable.
if (terminate) throw new InvalidOperationException();

// Do some work.

Thread.MemoryBarrier(); // Ensure a fresh read of the terminate variable.
if (terminate) throw new InvalidOperationException();

// Return computed metadata...
};

IAsyncResult result = work.BeginInvoke(null, null);
terminate = !result.AsyncWaitHandle.WaitOne(timeout);
return work.EndInvoke(result); // This blocks until the delegate completes.
}

棘手的部分是如何处理委托(delegate)内部的阻塞调用。显然,您无法检查 terminate标记代理是否处于阻塞调用的中间。但是,假设阻塞调用是从一种固定的 BCL 等待机制( WaitHandle.WaitOneMonitor.Wait 等)发起的,那么您可以使用 Thread.Interrupt “戳”它,应该会立即解锁它。

关于c# - 在实现时间受限的方法时,我应该中止工作线程还是让其自行运行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4503757/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com