繁体   English   中英

杀死阻塞另一个子进程的长时间运行的线程以结束

[英]killing a long running thread that is blocking on another child process to end

所以,有点背景。 我有一个程序可以创建一个长期运行的子进程,并执行一些我们对此问题并不真正关心的处理。 它存在,并且需要保持存在。 因此,在启动该子进程后,我启动一个线程来监视该子进程并阻止等待它通过 Process.WaitForExit() 结束,如果它结束,它将重新启动子进程,然后再次等待。 现在的问题是,我如何优雅地关闭所有这些? 如果我先杀死子进程,等待它的线程会再次启动它,所以我知道需要先杀死观察者线程。 我一直在通过 Thread.Abort() 执行此操作,然后仅捕获 ThreadAbortException 并返回结束观察者线程,然后我杀死了我的子进程。 但是有人告诉我,应该不惜一切代价避免使用 Thread.Abort() 并且 .Net 核心可能不再支持? 所以我的问题是,如果我捕捉到 ThreadAbortException,为什么 Thread.Abort() 如此危险? 什么是立即杀死该线程的最佳做法,这样它就没有机会在关闭期间再次启动子线程?

您正在寻找的是跨线程通信的方式。 有多种方法可以做到这一点,但它们都有适用的特定条件。

例如,互斥量和信号量可跨进程使用。 事件或等待句柄特定于给定进程等。一旦了解了这些细节,您就可以使用它们将信号从一个线程发送到另一个线程。

满足您要求的简单设置可以是 -

  1. 在产生任何线程之前创建一个重置事件。
  2. 让子线程开始。 在您的父母中等待您创建的重置事件。
  3. 让子线程重置事件。
  4. 在您的父线程中,等待状态已完成,您可以采取进一步的操作,例如再次启动线程并等待它,或者只是清理并退出执行。

Thread.Abort 是完成处理的一种不干净的方式。 如果您在此处阅读 msdn 文章 - https://docs.microsoft.com/en-us/dotnet/api/system.threading.thread.abort?view=net-6.0该评论清楚地告诉您您无法确定是什么您的线程执行的当前状态。您的线程可能没有机会跟进重要的清理任务,例如释放不再需要的资源。

如果您有更复杂的构造,这也可能导致死锁,例如线程从受保护的代码区域中止,例如 catch 块或 finally 块。 如果调用 Abort 的线程持有被中止线程正在等待的锁,则可能会获得死锁。

在多线程中要记住的关键是,您有责任让逻辑有一种干净的方式来完成并完成线程的执行。

请注意,上面建议的步骤是一种方法。 根据您的要求,它可以进一步重组/改进。 例如,如果您正在生成另一个进程,您将需要内核级别的对象,例如互斥锁或信号量。 像事件或标志这样的对象不能在整个过程中工作。

阅读此处 - https://docs.microsoft.com/en-us/dotnet/standard/threading/overview-of-synchronization-primitives了解更多信息。

您应该将等待线程更改为使用async 例如,你可以做这样的事情。

static async Task RunProcessWithRestart()
{
    using cancel = new CancellationTokenSource();
    try
    {
        while (true)
        {
            using (var process = CreateMyProcessAndStart())
            {
                await process.WaitForExitAsync(cancel.Token);
            }
        }
    }
    catch(OperationCanceledException)
    {
    }
}

static CancellationTokenSource cancel;

public static void StartWaitForProcess()
{
    Task.Run(RunProcessWithRestart);
}

public static void ShutdownWaitForProcess()
{
    cancel.Cancel();
}

另一种不需要从单独的关闭函数调用Cancel()的方法是订阅AppDomain.ProcessExit事件。

static async Task RunProcessWithRestart()
{
    using var cancel = new CancellationTokenSource();
    AppDomain.ProcessExit += (s, e) => cancel.Cancel();
    try
    {
        while (true)
        {
            using (var process = CreateMyProcessAndStart())
            {
                await process.WaitForExitAsync(cancel.Token);
            }
        }
    }
    catch(OperationCanceledException)
    {
    }
}

public static void StartWaitForProcess()
{
    Task.Run(RunProcessWithRestart);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM