Lio*_*oft 16 c# jobs termination process terminate
任务:如果父进程终止,则自动终止所有子进程.父进程不仅可以以正确的方式终止,还可以通过在ProcessExplorer中进行终止来终止.我该怎么做?
在С主题建议中使用Job对象的类似问题.如何在C#中使用它而不导出外部DLL?
我试着使用Job Objects.但是这段代码不能正常工作:
var job = PInvoke.CreateJobObject(null, null);
var jobli = new PInvoke.JOBOBJECT_BASIC_LIMIT_INFORMATION();
jobli.LimitFlags = PInvoke.LimitFlags.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
| PInvoke.LimitFlags.JOB_OBJECT_LIMIT_PRIORITY_CLASS
| PInvoke.LimitFlags.JOB_OBJECT_LIMIT_JOB_TIME
| PInvoke.LimitFlags.JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION
| PInvoke.LimitFlags.JOB_OBJECT_LIMIT_JOB_MEMORY;
var res = PInvoke.SetInformationJobObject(job, PInvoke.JOBOBJECTINFOCLASS.JobObjectBasicLimitInformation, jobli, 48);
if (!res)
{
int b = PInvoke.GetLastError();
Console.WriteLine("Error " + b);
}
var Prc = Process.Start(...);
PInvoke.AssignProcessToJobObject(job, Prc.Handle);
Run Code Online (Sandbox Code Playgroud)
PInvoke.SetInformationJobObject返回错误.GetLastError返回错误24.但是,PInvoke.AssignProcessToJobObject工作,子进程添加到作业队列(我可以在ProcessExplorer中看到它).但是,因为PInvoke.SetInformationJobObject不起作用 - 当我杀死父节点时,生成的进程保持活动状态.
我在这段代码中有什么不正确的地方?
小智 9
我尝试了上面的代码,事实上,它不起作用,抱怨一个不好的大小.原因是所使用的结构根据主机平台改变大小; 原始代码片段(在十几个网站上看到)假设一个32位应用程序.
将结构切换到此(请注意IntPtr调整大小成员),它将起作用.至少它对我有用.
[StructLayout(LayoutKind.Sequential)]
struct JOBOBJECT_BASIC_LIMIT_INFORMATION
{
public Int64 PerProcessUserTimeLimit;
public Int64 PerJobUserTimeLimit;
public Int16 LimitFlags;
public UIntPtr MinimumWorkingSetSize;
public UIntPtr MaximumWorkingSetSize;
public Int16 ActiveProcessLimit;
public Int64 Affinity;
public Int16 PriorityClass;
public Int16 SchedulingClass;
}
Run Code Online (Sandbox Code Playgroud)
要在Windows上终止进程树,只给出父进程或进程ID,您需要遍历进程树.
为此,您需要一种方法来获取给定进程的父进程ID.
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Diagnostics;
using System.Management;
namespace KillProcessTree
{
public static class MyExtensions
{
public static int GetParentProcessId(this Process p)
{
int parentId = 0;
try
{
ManagementObject mo = new ManagementObject("win32_process.handle='" + p.Id + "'");
mo.Get();
parentId = Convert.ToInt32(mo["ParentProcessId"]);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
parentId = 0;
}
return parentId;
}
}
Run Code Online (Sandbox Code Playgroud)
一旦你拥有了它,实际上杀死树并不难.
class Program
{
/// <summary>
/// Kill specified process and all child processes
/// </summary>
static void Main(string[] args)
{
if (args.Length < 1)
{
Console.WriteLine("Usage: KillProcessTree <pid>");
return;
}
int pid = int.Parse(args[0]);
Process root = Process.GetProcessById(pid);
if (root != null)
{
Console.WriteLine("KillProcessTree " + pid);
var list = new List<Process>();
GetProcessAndChildren(Process.GetProcesses(), root, list, 1);
// kill each process
foreach (Process p in list)
{
try
{
p.Kill();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
else
{
Console.WriteLine("Unknown process id: " + root);
}
}
/// <summary>
/// Get process and children
/// We use postorder (bottom up) traversal; good as any when you kill a process tree </summary>
/// </summary>
/// <param name="plist">Array of all processes</param>
/// <param name="parent">Parent process</param>
/// <param name="output">Output list</param>
/// <param name="indent">Indent level</param>
private static void GetProcessAndChildren(Process[] plist, Process parent, List<Process> output, int indent)
{
foreach (Process p in plist)
{
if (p.GetParentProcessId() == parent.Id)
{
GetProcessAndChildren(plist, p, output, indent + 1);
}
}
output.Add(parent);
Console.WriteLine(String.Format("{0," + indent*4 + "} {1}", parent.Id, parent.MainModule.ModuleName));
}
}
} // namespace
Run Code Online (Sandbox Code Playgroud)
您可以ProcessID
将父进程作为参数传递给子进程。然后子进程将负责时不时地检查父进程是否仍在运行。(通过调用Process.GetProcessById
。)
跟踪父进程存在的另一种方法是使用Mutex
同步原语。父应用程序最初将创建一个全局互斥体,其名称为子应用程序所知。孩子们可以不时检查互斥体是否仍然存在,如果不存在则终止。(一旦父进程关闭,互斥体将被系统自动销毁,无论其关闭方式如何。)