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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从零起步:开启你的IT职业之旅

简介&#xff1a; 信息技术&#xff08;IT&#xff09;行业以其快速发展和广阔的就业前景吸引着全球众多职场新人。但对于零基础的求职者而言&#xff0c;挺进这一行业似乎是条充满挑战的道路。进入IT行业可能看起来是一项艰巨的挑战&#xff0c;尤其是对于那些没有任何相关经…

redis乱码\xac\xed\x00\x05t\x00H解决

发现数据库乱码&#xff1a; 这数据库是来自rdids队列list实现的一个简单队列&#xff0c;停止使用该list的服务&#xff0c;查看里面的值&#xff0c;发现 乱码\xac\xed\x00\x05t\x00H&#xff0c;如下图&#xff1a; 很明发送数据端的问题&#xff0c;检查代码&#xff1a; …

20240403在ubuntu20.04下解压缩gz压缩包

20240403在ubuntu20.04下解压缩gz压缩包.txt 2024/4/3 15:17 缘起&#xff1a;使用友善之臂FriendlyElec的NanoPi NEO Core开发板 https://wiki.friendlyelec.com/wiki/index.php/NanoPi_NEO/zh#.E8.BF.90.E8.A1.8CFriendlyCore NanoPi NEO/zh http://wiki.friendlyelec.com/w…

人工智能会拥有反思能力吗?

一、背景 人工智能是否能拥有真正的反思能力&#xff0c;目前仍在探索和发展之中。虽然现有的AI系统可以在一定程度上进行自我学习、自我调整和优化&#xff0c;但是它们的“反思”还远未达到人类意义上的深度和全面性。 传统的人工智能系统依赖于预设的算法和模型&#xff0c…

微信小程序怎么制作?制作一个微信小程序需要多少钱?

随着移动互联网的快速发展&#xff0c;微信小程序已成为连接用户与服务的重要桥梁。它以其便捷性和易用性&#xff0c;为各类企业和个人提供了一个全新的展示和交易平台。那么&#xff0c;如何制作一个微信小程序&#xff1f;又需要投入多少资金呢&#xff1f;本文将为您提供全…

C++实现二叉搜索树的增删查改(非递归玩法)

文章目录 一、二叉搜索树的概念结构和时间复杂度二、二叉搜索树的插入三、二叉搜索树的查找四、二叉搜索树的删除&#xff08;最麻烦&#xff0c;情况最多&#xff0c;一一分析&#xff09;3.1首先我们按照一般情况下写&#xff0c;不考虑特殊情况下4.1.1左为空的情况&#xff…

【HTML】简单制作一个动态3D正方体

目录 前言 开始 HTML部分 JS部分 CSS部分 效果图 总结 前言 无需多言&#xff0c;本文将详细介绍一段代码&#xff0c;具体内容如下&#xff1a; 开始 首先新建文件夹&#xff0c;创建两个文本文档&#xff0c;其中HTML的文件名改为[index.html]&#xff0c;JS的文件名改…

win11安装wsl报错:无法解析服务器的名称或地址

一 说明 项目开发中&#xff0c;需要用到wsl&#xff0c;因此根据wsl官方&#xff08;WSL安装教程&#xff09;命令 wsl --install 进行wsl的安装。而本文主要是记录自己在安装wsl中遇到的问题 “无法解析服务器的名称或地址” 的解决办法。 二 方法一&#xff1a;更改DNS&…

HCIA-RS基础-VLAN技术原理和配置

目录 VLAN 技术原理和配置1. VLAN 技术的背景2. VLAN 标签的产生方法3. VLAN 标签的应用规则4. VLAN 的配置总结 VLAN 技术原理和配置 1. VLAN 技术的背景 VLAN&#xff08;Virtual Local Area Network&#xff09;是一种逻辑上划分网络的技术&#xff0c;可以将一个物理局域…

算法打卡day25

今日任务&#xff1a; 1&#xff09;491.递增子序列 2&#xff09;46.全排列 3&#xff09;47.全排列 II 491.递增子序列 题目链接&#xff1a;491. 非递减子序列 - 力扣&#xff08;LeetCode&#xff09; 给定一个整型数组, 你的任务是找到所有该数组的递增子序列&#xff0c…

composure合成透明通道

composure合成透明通道 2022-05-23 08:59 [技巧分享]使用配有HDRI的背板的进行合成 Using Composure with a Bac - 1.Using Composure with a Backplate and H.mp41启用插件2线性色彩空间3打开合成面板4面板新建合成新建三个图层 FG前面物体&#xff0c;背景物体 去掉阴影 flo…

Zabbix6 - Web管理网络拓扑/端口流量监控配置手册

Zabbix6 - Web管理网络拓扑/端口流量监控配置手册 概述: 1)Zabbix能监视各种网络参数,保证服务器系统的安全运营;并提供灵活的通知机制以让系统管理员快速定位/解决存在的各种问题。 Zabbix由两部分构成,Zabbix Server与可选组件Zabbix Agent。通过C/S模式采集数据,通过B…

60道Java经典面试题总结

1、Spring 有几种配置方式&#xff1f; 1、xml 配置文件 <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.springframework.org/schema/beans"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:…

量化交易入门(四十一)ASI指标Python实现和回测

老规矩先上图&#xff0c;看看ASI指标使用苹果数据回测后的结果如何。 一、策略运行结果 执行的结果&#xff1a; Starting Portfolio Value: 100000.00 Final Portfolio Value: 92514.82 Annualized Return: -1.93% Sharpe Ratio: -0.27 Max Drawdown: 25.34% Max Drawdown …

【教学类-09-04】20240401细线迷宫图03(A4横版一页-4份横版)

作品展示&#xff1a; 背景需求&#xff1a; 【教学类-09-02】20240331细线迷宫图01&#xff08;A4横版一页1份横版&#xff09;-CSDN博客文章浏览阅读779次&#xff0c;点赞28次&#xff0c;收藏6次。【教学类-09-02】20240331细线迷宫图01&#xff08;A4横版一页1份横版&…

机器学习周记(第三十二周:文献阅读-时空双通路框架)2024.3.25~2024.3.31

目录 摘要 ABSTRACT 1 论文信息 1.1 论文标题 1.2 论文摘要 1.3 论文模型 1.3.1 Spatial Encoder&#xff08;空间编码器&#xff09; 1.3.2 Temporal Encoder&#xff08;时间编码器&#xff09; 2 相关代码 摘要 本周阅读了一篇运用GNN进行时间序列预测的论文。论文…

【数据处理包Pandas】分组及相关操作

目录 一、初步认识分组并查看分组信息&#xff08;一&#xff09;通过聚合函数查看分组信息&#xff08;二&#xff09;转换成列表查看所有组的信息&#xff08;三&#xff09;通过循环查看各组的名称和组中的数据信息&#xff08;四&#xff09;通过get_group()方法直接获得一…

【蓝桥杯练习】tarjan算法求解LCA

还是一道比较明显的求LCA(最近公共祖先)模型的题目,我们可以使用多种方法来解决该问题&#xff0c;这里我们使用更好写的离线的tarjan算法来解决该问题。 除去tarjan算法必用的基础数组&#xff0c;我们还有一个数组d[],d[i]记录的是每个点的出度&#xff0c;也就是它的延迟时间…

高级IO/多路转接-select/poll(1)

概念背景 IO的本质就是输入输出 刚开始学网络的时候&#xff0c;我们简单的写过一些网络服务&#xff0c;其中用到了read&#xff0c;write这样的接口&#xff0c;当时我们用的就是基础IO&#xff0c;高级IO主要就是效率问题。 我们在应用层调用read&&write的时候&…

YOLOv2

YOLOv2 论文介绍论文改进1. Batch Normalization2. High Resolution Classifier3. Convolutional With Anchor Boxes4. vgg16换成darknet-195. Dimension Clusters&#xff08;w h的聚类&#xff09;6 预测坐标7. passthrough8. 多尺度输入训练 损失函数 论文介绍 论文名字&am…