C# 中父进程终止对子进程终止的影响
在软件开发中,处理父进程终止时子进程的行为对于维护系统稳定性至关重要。当多个子进程由父进程生成时,确保它们与父进程一起终止非常重要。本文讨论了一个常见问题:使用 System.Diagnostics.Process
类生成的子进程即使在主应用程序崩溃或通过任务管理器强制终止时仍然存在。
作业对象:解决父子进程层次结构的方案
为了建立子进程和父进程之间的依赖关系,可以使用称为“作业对象”的功能。作业对象允许在进程之间创建层次关系,其中父作业对象的终止也会导致所有关联的子进程终止。
以下代码演示了如何使用作业对象来管理子进程依赖关系:
<code class="language-csharp">using System; using System.Runtime.InteropServices; using System.Diagnostics; public class Job : IDisposable { [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] static extern IntPtr CreateJobObject(IntPtr a, string lpName); [DllImport("kernel32.dll")] static extern bool SetInformationJobObject(IntPtr hJob, JobObjectInfoType infoType, IntPtr lpJobObjectInfo, uint cbJobObjectInfoLength); [DllImport("kernel32.dll", SetLastError = true)] static extern bool AssignProcessToJobObject(IntPtr job, IntPtr process); private IntPtr _handle; private bool _disposed = false; public Job() { _handle = CreateJobObject(IntPtr.Zero, null); JOBOBJECT_BASIC_LIMIT_INFORMATION info = new JOBOBJECT_BASIC_LIMIT_INFORMATION(); info.LimitFlags = 0x2000; // JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE JOBOBJECT_EXTENDED_LIMIT_INFORMATION extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION(); extendedInfo.BasicLimitInformation = info; int length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); IntPtr extendedInfoPtr = Marshal.AllocHGlobal(length); Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false); if (!SetInformationJobObject(_handle, JobObjectInfoType.ExtendedLimitInformation, extendedInfoPtr, (uint)length)) throw new Exception($"无法设置信息。错误:{Marshal.GetLastWin32Error()}"); Marshal.FreeHGlobal(extendedInfoPtr); } public void AddProcess(Process process) { if (!AssignProcessToJobObject(_handle, process.Handle)) throw new Exception($"无法将进程分配到作业对象。错误:{Marshal.GetLastWin32Error()}"); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (_disposed) return; if (disposing) { } Close(); _disposed = true; } public void Close() { if (_handle != IntPtr.Zero) { Win32.CloseHandle(_handle); _handle = IntPtr.Zero; } } } internal static class Win32 { [DllImport("kernel32.dll")] internal static extern bool CloseHandle(IntPtr hObject); } // 必要的结构体定义 (根据需要补充完整) enum JobObjectInfoType { ExtendedLimitInformation = 9 } [StructLayout(LayoutKind.Sequential)] internal struct IO_COUNTERS { public UInt64 ReadOperationCount; public UInt64 WriteOperationCount; public UInt64 OtherOperationCount; public UInt64 ReadTransferCount; public UInt64 WriteTransferCount; public UInt64 OtherTransferCount; } [StructLayout(LayoutKind.Sequential)] internal struct JOBOBJECT_BASIC_LIMIT_INFORMATION { public Int64 PerProcessUserTimeLimit; public Int64 PerJobUserTimeLimit; public UInt32 LimitFlags; public UIntPtr MinimumWorkingSetSize; public UIntPtr MaximumWorkingSetSize; public UInt32 ActiveProcessLimit; public UInt32 Affinity; public UInt32 PriorityClass; public UInt32 SchedulingClass; } [StructLayout(LayoutKind.Sequential)] internal struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION { public JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation; public IO_COUNTERS IoInfo; public UInt64 ProcessMemoryLimit; public UInt64 JobMemoryLimit; public UInt64 PeakProcessMemoryUsed; public UInt64 PeakJobMemoryUsed; }</code>
在创建子进程后,调用 AddProcess()
方法将其与已建立的作业对象关联。 注意代码中添加了必要的结构体定义和IDisposable
接口的实现,以及对资源的正确释放。
以上是当父程进程以C#结束时,如何确保子进程终止?的详细内容。更多信息请关注PHP中文网其他相关文章!