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が実行されていることがわかります-「MicrosoftApplicationErrorReporting」プログラム。そして、それはただ...そこにあり、コンソールアプリはメモリに残ります。
この継続的なCPUスパイクと解放されていないメモリを回避するために、プロセスを正しく終了するには、ここで何をする必要がありますか?最終的に、これは介入なしで実行する必要があります。
PSここでは、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)を試行します。