C# 实现子进程跟随主进程关闭

文章目录

  • 前言
  • 一、如何实现?
    • 1、创建作业对象
      • (1)、创建对象
      • (2)、设置销毁作业时,关闭拥有的进程
    • 2、子进程加入作业对象
    • 3、销毁作业对象
      • (1)、手动销毁
      • (2)、所在进程结束自动销毁
  • 二、完整代码
  • 三、使用示例
    • 1、正常退出自动结束子进程
    • 2、异常退出自动结束子进程
  • 总结


前言

多进程开发经常会遇到主进程关闭,子进程需要跟随主进程一同关闭。比如调ffmpeg命令行实现的录屏程序,录屏程序关闭,ffmpeg进程也需要退出。我们通常在程序关闭时调用Process.Kill()杀掉fmpeg进程即可。但是如果是强制或异常关闭录屏程序,ffmpeg将会变成僵尸进程残留在系统中。本文将提供一种解决此类问题的方法。


一、如何实现?

1、创建作业对象

(1)、创建对象

handle = CreateJobObject(IntPtr.Zero, null);

(2)、设置销毁作业时,关闭拥有的进程

var info = new JOBOBJECT_BASIC_LIMIT_INFORMATION
{
    LimitFlags = 0x2000
};
var extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION
{
    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(string.Format("Unable to set information.  Error: {0}", Marshal.GetLastWin32Error()));

2、子进程加入作业对象

AssignProcessToJobObject(handle, processHandle);

3、销毁作业对象

(1)、手动销毁

CloseHandle(handle);

(2)、所在进程结束自动销毁


二、完整代码

using System.Diagnostics;
using System.Runtime.InteropServices;
namespace JobManagement
{
    #region Helper classes
    /// <summary>
    ///  作业对象,主要用于子进程管理。
    ///  目前版本是只支持作业销毁拥有的子进程退出
    ///  通常可以定义一个全局静态变量使用
    /// </summary>
    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, UInt32 cbJobObjectInfoLength);
        [DllImport("kernel32.dll", SetLastError = true)]
        static extern bool AssignProcessToJobObject(IntPtr job, IntPtr process);
        [DllImport("kernel32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool CloseHandle(IntPtr hObject);
        private IntPtr handle;
        private bool disposed;
        public Job()
        {
            handle = CreateJobObject(IntPtr.Zero, null);
            var info = new JOBOBJECT_BASIC_LIMIT_INFORMATION
            {
                LimitFlags = 0x2000
            };
            var extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION
            {
                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(string.Format("Unable to set information.  Error: {0}", Marshal.GetLastWin32Error()));
        }
        /// <summary>
        /// 进程加入到作业对象中
        /// </summary>
        /// <param name="processHandle">进程句柄</param>
        /// <returns></returns>
        public bool AddProcess(IntPtr processHandle)
        {
            return AssignProcessToJobObject(handle, processHandle);
        }

        /// <summary>
        /// 进程加入到作业对象中
        /// </summary>
        /// <param name="processId">进程Id</param>
        /// <returns></returns>
        public bool AddProcess(int processId)
        {
            return AddProcess(Process.GetProcessById(processId).Handle);
        }
        /// <summary>
        /// 销毁作业对象,手动调用则其拥有的所有进程都会退出
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        /// <summary>
        /// 销毁作业对象,手动调用则其拥有的所有进程都会退出
        /// </summary>
        public void Close()
        {
            CloseHandle(handle);
            handle = IntPtr.Zero;
        }
        private void Dispose(bool disposing)
        {
            if (disposed)
                return;
            if (disposing) { }
            Close();
            disposed = true;
        }
    }

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

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

    [StructLayout(LayoutKind.Sequential)]
    public struct SECURITY_ATTRIBUTES
    {
        public UInt32 nLength;
        public IntPtr lpSecurityDescriptor;
        public Int32 bInheritHandle;
    }

    [StructLayout(LayoutKind.Sequential)]
    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;
    }

    public enum JobObjectInfoType
    {
        AssociateCompletionPortInformation = 7,
        BasicLimitInformation = 2,
        BasicUIRestrictions = 4,
        EndOfJobTimeInformation = 6,
        ExtendedLimitInformation = 9,
        SecurityLimitInformation = 5,
        GroupInformation = 11
    }
    #endregion
}

三、使用示例

1、正常退出自动结束子进程

.net8.0

using System.Diagnostics;
using JobManagement;
//创建作业对象
Job _job = new Job();
//打开记事本程序
var ps = new Process();
ps.StartInfo.FileName = "notepad.exe";
ps.Start();
//记事本程序进程加入到作业对象
_job.AddProcess(ps.Handle);
//等待3秒后退出程序,记事本程序会自动关闭
Thread.Sleep(3000);

效果预览
在这里插入图片描述

2、异常退出自动结束子进程

.net8.0

using System.Diagnostics;
using JobManagement;
//创建作业对象
Job _job = new Job();
//打开记事本程序
var ps = new Process();
ps.StartInfo.FileName = "notepad.exe";
ps.Start();
//记事本程序进程加入到作业对象
_job.AddProcess(ps.Handle);
while(true)Thread.Sleep(3000);

效果预览
在这里插入图片描述


总结

以上就是今天要讲的内容,本文讲述的内容是windows多进程开发中比较重要的技术,因为大部分场景主进程退出后子进程应该跟随退出,正常流程中通过代码可以在退出时关闭所有子进程,但是异常崩溃时则不行,会出现遗留子进程。而本文的方法就很好的解决的这个问题,而且也不需要编写任何关闭子进程的相关代码,方便且省心。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/517142.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

git 常用命令和使用方法

1.git理论基础 1.1git简介 git是一个开源的分布式版本控制系统&#xff0c;可以有效、高速地处理从很小到非常大的项目版本管理。 1.2git工作流程 在工作目录中&#xff0c;添加、修改文件将需要进行版本管理的文件放入暂存区中将暂存区域的文件提交到git仓库中 2.git基本…

SQLite的架构(十一)

返回&#xff1a;SQLite—系列文章目录 上一篇&#xff1a;SQLite下一代查询规划器(十&#xff09; 下一篇&#xff1a;SQLite—系列文章目录 介绍 本文档介绍SQLite库的架构。 这里的信息对那些想要了解或 修改SQLite的内部工作原理。 接口SQL 命令处理器虚拟机B-树…

ids工业相机与电控位移台同步控制及数据采集

通过VS2017和OpenCV,实现ids工业相机与电控位移台同步控制及数据采集 目录项目环境配置代码流程及思路项目架构项目开发运行效果开发关键ids相机配置位移台环境配置相机头文件相机参数设置保存图像函数设置电控位移台头文件电控位移台设置参数最后就是通过main函数进行调用和控…

CCIE-08-BGP-Listen

目录 实验条件网络拓朴实验目的 开始配置配置动态路由协议配置BGP检查邻居配置 实验条件 网络拓朴 实验目的 将R1配置成Listen状态&#xff0c;自动接收来自其它路由器的建邻居请求、建立邻居 开始配置 配置动态路由协议 这里用EIGRP来配置&#xff0c;保证网络的可达性&a…

Linux云计算之Linux基础2——Linux发行版本的安装

目录 一、彻底删除VMware 二、VMware-17虚拟机安装 三、MobaXterm 安装 四、Centos 发行版 7.9的安装 五、rockys 9.1的安装 六、ubuntu2204的安装 一、彻底删除VMware 在卸载VMware虚拟机之前&#xff0c;要先把与VMware相关的服务和进程终止 1. 在windows中按下【Windo…

open-cd框架调试记录

源于论文Changer: Feature Interaction Is What You Need forChange Detection 源码位置&#xff1a;open-cd/README.md at main likyoo/open-cd (github.com) 同样是基于MMSegmentation框架的代码&#xff0c;不符合本人编程习惯所以一直也没有研究这东西&#xff0c;近期打…

Gitee上传私有仓库

个人记录 Gitee创建账号 以KS进销存系统为例&#xff0c;下载到本地电脑解压。 新建私有仓库 仓库名称&#xff1a;ks-vue3&#xff0c;选择‘私有’ 本地配置 下载安装git配置git 第一次配置可以在本地目录右键【Open Git Bash here】输入【Git 全局设置】再输入【创…

IDEA配置本地Maven(解决依赖下载缓慢)

1.下载Maven Maven下载页 根据需要选择下载其中一个&#xff0c;我选了zip格式的 将下载好的apache-maven-3.9.5解压到你想要的目录下 2.配置系统环境 设置系统环境变量 MAVEN_HOME 为安装路径的bin目录 变量名&#xff1a;MAVEN_HOME 变量值&#xff1a;写你的 apache-m…

网络安全 | 什么是负载均衡器?

关注WX&#xff1a; CodingTechWork 介绍 负载均衡是在多个服务器之间有效分配网络流量的过程。负载均衡的目的是优化应用程序的可用性&#xff0c;并确保良好的终端用户体验。负载均衡可协助高流量网站和云计算应用程序应对数百万个用户请求&#xff0c;从而保证客户请求不会…

C#/WPF Inno Setup打包程序

Inno Setup介绍 Inno Setup 是一个免费的 Windows 安装程序制作软件。第一次发表是在 1997 年&#xff0c;现在已经更新到Inno Setup 6了。Inno Setup是一个十分简单实用的打包小工具&#xff0c;可以按照我们自己的意愿设置功能&#xff0c;稳定性也很好。 官方网址&#xff1…

腾讯云4核8G12M服务器和标准型S5服务器配置价格表

2024年腾讯云4核8G服务器租用优惠价格&#xff1a;轻量应用服务器4核8G12M带宽646元15个月&#xff0c;CVM云服务器S5实例优惠价格1437.24元买一年送3个月&#xff0c;腾讯云4核8G服务器活动页面 txybk.com/go/txy 活动链接打开如下图&#xff1a; 腾讯云4核8G服务器优惠价格 轻…

746.Leetcode 使用最小花费爬楼梯

746.Leetcode 使用最小花费爬楼梯 给你一个整数数组 cost &#xff0c;其中 cost[i] 是从楼梯第 i 个台阶向上爬需要支付的费用。一旦你支付此费用&#xff0c;即可选择向上爬一个或者两个台阶。 你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。 请你计算并返回达到楼梯…

【Qt】:常用控件(四:显示类控件)

常用控件 一.Lable二.LCD Number 一.Lable QLabel 可以⽤来显⽰⽂本和图⽚. 代码⽰例:显⽰不同格式的⽂本 代码⽰例:显⽰图⽚ 此时,如果拖动窗⼝⼤⼩,可以看到图⽚并不会随着窗⼝⼤⼩的改变⽽同步变化 为了解决这个问题,可以在Widget中重写resizeEvent函数。当用户把窗口从A拖…

大商创多用户商城系统 多处SQL注入漏洞复现

0x01 产品简介 大商创多用户商城系统是一个功能强大、灵活多变的新零售电商系统服务商。该系统支持平台自营和商家入驻,实现多元化经营模式,能够全面整合供应商、生产商、经销商和消费者等产业链资源,提高产品多样性,加快资金流动速度,并有助于减少不必要的成本输出。 0…

代码审计-PHP原生开发篇SQL注入数据库监控正则搜索文件定位静态分析

文章目录 前言1、Bluecms-CNVD-1Day-常规注入审计分析2、emlog-CNVD-1Day-常规注入审计分析3、emlog-CNVD-1Day-2次注入审计分析 前言 挖掘技巧&#xff1a; -语句监控-数据库SQL监控排查可利用语句定向分析 -功能追踪-功能点文件SQL执行代码函数调用链追踪 -正则搜索-(update…

【MATLAB源码-第178期】基于matlab的8PSK调制解调系统频偏估计及补偿算法仿真,对比补偿前后的星座图误码率。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 在通信系统中&#xff0c;频率偏移是一种常见的问题&#xff0c;它会导致接收到的信号频率与发送信号的频率不完全匹配&#xff0c;进而影响通信质量。在调制技术中&#xff0c;QPSK&#xff08;Quadrature Phase Shift Keyi…

C语言进阶课程学习记录-第22课 - 条件编译使用分析

C语言进阶课程学习记录-第22课 - 条件编译使用分析 条件编译基本概念条件编译实验条件编译本质实验-ifdefinclude本质实验-间接包含同一个头文件解决重复包含的方法-ifndef实验-条件编译的应用小结 本文学习自狄泰软件学院 唐佐林老师的 C语言进阶课程&#xff0c;图片全部来源…

深入理解指针2:数组名理解、一维数组传参本质、二级指针、指针数组和数组指针

1、数组名理解 首先来看一段代码&#xff1a; int main() {int arr[10] { 1,2,3,4,5,6,7,8,9,10 };printf("%d\n", sizeof(arr));return 0; } 输出的结果是&#xff1a;40&#xff0c;如果arr是数组首元素的地址&#xff0c;那输出应该是4/8才对。 其实数组名就…

WordPress主题–Applay v3.7.1 开心版下载

Applay是一款功能强大的多用途WordPress主题&#xff0c;专为应用展示、应用商店、商业和购物等Woocommerce网站而设计。它配备了拖曳式页面编辑功能&#xff0c;类似于Elementor&#xff0c;让您能够轻松构建和定制您的网站。无论您有什么需求&#xff0c;都可以尝试下这个主题…

时序预测 | Matlab基于CFBP级联前向BP神经网络时序预测

时序预测 | Matlab基于CFBP级联前向BP神经网络时序预测 目录 时序预测 | Matlab基于CFBP级联前向BP神经网络时序预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.Matlab基于CFBP级联前向BP神经网络时序预测&#xff08;完整源码和数据)&#xff1b; 2.数据集为excel…