0

我正在编写一个在.NET 中使用提供者模型模式的小型应用程序。每个提供者都有一种方法可以实现,以便在我的应用程序中插入。

我想在不同的线程中运行所有提供者的特定工作(实现的方法),但是当一个任务完成时,所有其他任务都需要停止执行。

我在 .NET 中使用带有 CancellationToken 的 async/await 模型来取消任务。

tasks.Add(Task.Run(() =>
                {
                        if (token.IsCancellationRequested)
                            token.ThrowIfCancellationRequested();

                        return provider.DoWork();

                }, token));

while (tasks.Count > 0)
        {
            var t = await Task.WhenAny(tasks);

            tasks.Remove(t);

            var result = await t;

            if (!string.IsNullOrEmpty(result))
            {
                tokenSource.Cancel();
                return result;
            }
        }

某些 provider.DoWork() 方法可能非常慢,并且要停止执行 DoWork 方法的线程,我必须在 DoWork 方法中检查 token.IsCancellationRequested 但我不能,因为这些方法是从其他人那里编写的,例如。在这种情况下,DoWork 之外的 token.IsCancellationRequested 检查并不重要。

总而言之,当一个任务完成时,其他任务必须停止,但无法访问每个线程中运行的代码。

期待听到您对此的看法。

4

2 回答 2

2

与突然终止进程中的线程相关的问题有很多——本质上,这应该作为最后的手段,当进程如此糟糕以至于你无论如何都将要杀死整个事情时。除此之外的任何事情,如果您进行干预,您将面临造成重大问题的严重风险。所以:留下优雅的选择性退出。您提到您已经在使用取消令牌;真的,这就是你所能做的(至少是安全的)。检查取消和退出取决于不同的实现。如果您不能依赖定期检查取消的任务:您有点卡住了。

基本上,您所描述的内容没有简单的答案。

于 2013-10-26T21:19:10.733 回答
0

有几种不同的方法可以阻止任意代码,但都不是理想的。

首先,您可以在线程级别处理此问题。换句话说,给每个提供者一个单独的线程,并Thread.Abort在您希望它停止时调用。不幸的是,这种方法存在无数问题:其中两个比较知名的问题是死锁的可能性,以及进入无法再在 AppDomain 中实例化类型的奇怪状态。出于这个原因,Thread.Abort被认为是“邪恶的”和明确的代码气味。

再上一层,您可以在 AppDomain 级别上解决此问题。在这种情况下,您给每个提供者一个单独的 AppDomain。这种方法的优点是您可以比线程更干净地关闭 AppDomain。不幸的是,有些事情仍然会从裂缝中溜走:特别是,非托管资源可能会从 AppDomain 泄漏到您的进程中。

这为您提供了最可靠的解决方案:在流程层面上解决这个问题。也就是说,你给每个提供者一个单独的进程,并使用进程间通信来控制它。一个进程可以干净地关闭,因为操作系统负责清理。不幸的是,这种方法开销最大并且最难编程。

一个强大的托管解决方案必须至少支持最后一个。例如,ASP.NET 支持所有这三种情况:请求线程可以在某些情况下中止(例如,客户端断开连接),AppDomain 可以被回收,这会升级到整个工作进程被回收的地方。但是,我建议您不要使用升级策略编写自己的托管平台。

我的建议是 1)CancellationToken向您的提供者提供并鼓励他们使用它,以及 2) 在您发出令牌信号后,让他们运行完成。

于 2013-10-27T00:19:00.627 回答