You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

通过任务管理器终止Windows服务父进程时如何同步杀死其子进程

解决方案

方案1:使用Windows Job Object(推荐,无需修改子进程,自动关联所有后代进程)

这是Windows内核原生提供的进程组管理机制,你可以在父服务进程中创建作业对象,设置JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE标记,将父进程自身加入该作业。当父进程被任务管理器终止时,父进程持有的作业对象句柄会被系统自动释放,触发作业规则,自动终止所有关联在该作业内的进程,包括你启动的子进程,甚至子进程后续启动的孙进程也会被同步清理。

修改后的父服务代码如下:

using System.Diagnostics;
using System.Runtime.InteropServices;
using Microsoft.Extensions.Hosting;

// parent service
class Program
{
    // 导入Win32 API
    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    private static extern IntPtr CreateJobObject(IntPtr lpJobAttributes, string lpName);

    [DllImport("kernel32.dll")]
    private static extern bool SetInformationJobObject(IntPtr hJob, JobObjectInfoType infoType, IntPtr lpJobObjectInfo, uint cbJobObjectInfoLength);

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool AssignProcessToJobObject(IntPtr hJob, IntPtr hProcess);

    private enum JobObjectInfoType
    {
        ExtendedLimitInformation = 9
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION
    {
        public JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation;
        public IO_COUNTERS IoInfo;
        public UIntPtr ProcessMemoryLimit;
        public UIntPtr JobMemoryLimit;
        public UIntPtr PeakProcessMemoryUsed;
        public UIntPtr PeakJobMemoryUsed;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct JOBOBJECT_BASIC_LIMIT_INFORMATION
    {
        public long PerProcessUserTimeLimit;
        public long PerJobUserTimeLimit;
        public uint LimitFlags;
        public UIntPtr MinimumWorkingSetSize;
        public UIntPtr MaximumWorkingSetSize;
        public uint ActiveProcessLimit;
        public UIntPtr Affinity;
        public uint PriorityClass;
        public uint SchedulingClass;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct IO_COUNTERS
    {
        public ulong ReadOperationCount;
        public ulong WriteOperationCount;
        public ulong OtherOperationCount;
        public ulong ReadTransferCount;
        public ulong WriteTransferCount;
        public ulong OtherTransferCount;
    }

    // 作业对象句柄,需要保持全局引用避免被GC回收
    private static IntPtr _jobHandle;

    static void Main(string[] args)
    {
        // 初始化作业对象
        _jobHandle = CreateJobObject(IntPtr.Zero, null);
        var extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION();
        // 设置关闭作业时终止所有关联进程的标记
        extendedInfo.BasicLimitInformation.LimitFlags = 0x2000; // JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE

        int length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
        IntPtr extendedInfoPtr = Marshal.AllocHGlobal(length);
        Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false);

        SetInformationJobObject(_jobHandle, JobObjectInfoType.ExtendedLimitInformation, extendedInfoPtr, (uint)length);
        // 将父进程自身加入作业,后续启动的子进程会自动继承作业关联,无需额外手动添加
        AssignProcessToJobObject(_jobHandle, Process.GetCurrentProcess().Handle);
        Marshal.FreeHGlobal(extendedInfoPtr);

        var host = Host
            .CreateDefaultBuilder(args)
            .UseWindowsService()
            .Build();

        var startInfo = new ProcessStartInfo
        {
            FileName = "Test.ChildProcessApp.exe"
        };

        Process.Start(startInfo);
        host.Run();
    }
}

方案2:父进程监听退出事件主动清理子进程

如果不想调用Win32 API,可以在父进程启动子进程时记录所有子进程实例,注册父进程的退出/中止事件,在事件触发时遍历杀掉所有记录的子进程。这个方案的缺陷是如果父进程被极端强制结束,可能来不及触发清理逻辑,导致子进程残留。

核心代码片段如下:

using System.Diagnostics;
using Microsoft.Extensions.Hosting;

// parent service
class Program
{
    // 存储所有启动的子进程实例
    private static List<Process> _childProcesses = new List<Process>();

    static void Main(string[] args)
    {
        // 注册进程退出事件
        AppDomain.CurrentDomain.ProcessExit += (s, e) =>
        {
            foreach (var p in _childProcesses)
            {
                if (!p.HasExited)
                {
                    p.Kill();
                    p.WaitForExit();
                }
            }
        };

        var host = Host
            .CreateDefaultBuilder(args)
            .UseWindowsService()
            .Build();

        var startInfo = new ProcessStartInfo
        {
            FileName = "Test.ChildProcessApp.exe"
        };

        var child = Process.Start(startInfo);
        _childProcesses.Add(child);

        host.Run();
    }
}

注意事项

  • 方案1是最优选择,兼容所有Windows主流版本,无论父进程是正常退出还是被强制终止,都能保证子进程被同步清理,且不需要额外维护子进程列表。
  • Windows服务默认运行在Session 0,以上两个方案在Session 0环境下均可以正常生效。

内容的提问来源于stack exchange,提问作者GY_

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 17:48:03