C#.NET 3.5

我有一个控制台应用程序正被计算机上的另一个应用程序调用。此控制台应用程序连续运行,并从“父”中侦听stdin上的数据。处理。

但是,当父级被停止或终止时,它启动的控制台应用程序将继续。在正常情况下,它使用最少的资源来等待来自stdin的输入。然而,一旦父母离开,这个控制台应用程序就会激活CPU并使其运行的核心匮乏,利用率接近100%。这一直持续到我手动终止进程。

理想情况下,主叫父母会自行清理,特别是因为这是在正常(非特殊)“停止”下发生的。条件。不幸的是,这个父进程不在我手中。

我的第一个想法是从控制台应用程序中获取调用父级,并监视其PID。如果父进程消失,我的控制台应用程序将自行终止。目前,我这样做是通过:

Process process = Process.GetCurrentProcess();
m_ParentPID = 0;
using (ManagementObject mgmtObj = new ManagementObject("win32_process.handle='" +     process.Id.ToString() + "'"))
{
    mgmtObj.Get();
    m_ParentPID = Convert.ToInt32(mgmtObj["ParentProcessId"]);
}
string parentProcessName = Process.GetProcessById(m_ParentPID).ProcessName;
Log("Parent Process: " + parentProcessName + Environment.NewLine);

// Create a timer for monitoring self.
Timer timer = new Timer(new TimerCallback(sender =>
{
    if (m_ParentPID != 0)
    {
        Process parent = System.Diagnostics.Process.GetProcessById(m_ParentPID);
        if (parent == null)
        {
            Log("Parent process stopped/killed.  Terminating self.");
            System.Environment.Exit(0);
        }
    }
}));

// Kick on the timer
timer.Change(m_ExitWatcherFrequency, m_ExitWatcherFrequency);

这只是部分工作 - 它会停止CPU峰值,但如果我从Sysinternals精彩流程监视器查看我的进程,我可以看到DW20.exe运行 - “Microsoft应用程序错误报告”程序。它只是......坐在那里,控制台应用程序仍然在内存中。

我应该在这里做什么来正确终止进程以避免这种持续的CPU峰值和未释放的内存?最终,这需要在没有干预的情况下运行。

P.S。我在这里使用命令行应用程序作为“长时间运行的程序”。而不是Windows服务或Web服务,因为父程序只能配置为执行命令行应用程序,它通过stdin传递数据。 (对于那些好奇的人来说,这是ejabberd,使用外部认证)。

编辑:

等待stdin输入的代码是:

// Read data from stdin
char[] charray = new char[maxbuflen];
read = Console.In.Read(charray, 0, 2);

之前我提到当父母终止时,控制台应用程序在CPU上发疯了。我从Visual Studio附加了一个调试器,实际上它仍然位于该行Console.In.Read上。理论上,当自我监视计时器触发并看到父进程已经消失时,当另一个线程在Read()行上时,它会尝试System.Environment.Exit(0)。

有帮助吗?

解决方案

听起来你的进程正在进入一个硬循环,因为当父进程退出时控制台输入流被关闭。您是否从 Console.In.Read 检查返回值?当流关闭时,它将返回零。此时突破循环,让 Main()方法自行退出。

如果您正在运行多个线程,则必须先使用 Thread.Join 或等效线程完成它们。

其他提示

要观察流程退出,请使用流程 class,并订阅已退出事件。

编辑:删除了互操作评论。

编辑(回应评论):

大多数情况下,在这种情况下所做的是将一些数据传回,因此您可以停止阻止 Console.In.Read 方法调用。

因此,假设您在发现父进程完成时将标志 IsDone 设置为true。现在,因为你正在等待的过程不再发送任何东西,你仍然需要在标准输入上接收一些东西,否则你将永远阻止。因此,在您的事件处理程序/计时器代码中,将某些内容写入您自己进程的标准输入(如果您需要,它甚至可以是一个特殊值来表示您已完成)。这将使您通过 Console.In.Read 方法。一旦出来,检查是否设置了 IsDone 标志 - 如果是,则停止处理并从main方法返回 - 不需要 System.Environment.Exit

我通过向您的控制台应用程序添加一个线程来解决这个问题,该线程基本上监视进程表中调用应用程序的存在。这一切都是我的头脑,但这里有一些假代码:

using System.Thread;
using System.Diagnostics;

main(){
     Thread monitoringThread = new Thread(new ThreadStart(monitor));
     monitoringThread.Name = "Monitor";
     monitoringThread.Start();
}

并在功能监视器中:

void monitor(){
     Process[] theCallers = Process.GetProcessesByName("CallingProcessName");
     theCallers[0].WaitForExit();
     Process.GetCurrentProcess().Kill();
}

假设您在进程列表中只有一个调用进程,那么只要该进程结束,这个进程就会出现。您也可以为自己的流程添加更好的清理代码,而不是让它突然结束。

我喜欢mmr从孩子那里看父母过程的想法。如果你有办法在命令行上传递父PID,那就更好了。从父进程内部,您可以获得PID:

System.Diagnostics.Process.GetCurrentProcess().Id
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top