当前位置:网站首页>Process实现守护线程
Process实现守护线程
2022-08-08 20:47:00 【郭麻花】
前言
需求是这样的:我们需要让一个桌面程序长期保持全屏状态,如果进程意外结束的话,必须即时的将它重新启动。我们可以使用Process类来做一个守护线程。
Process
提供对本地和远程进程的访问权限,并使你能够启动和停止本地系统进程。 Proess介绍
Process的静态方法GetProcesses()可以帮助我们获取到本地计算机上运行的所有进程资源,它的返回值是Process[] ps,其中每一个Process组件代表一个与之关联的进程资源。
Process[] ps = Process.GetProcesses();
DisplayProcess(ps);
我们可以从Process获取到与之关联的进程信息
static void DisplayProcess(IEnumerable<Process> ps)
{
int i = 1;
foreach (Process p in ps)
{
try
{
WriteLine($"{i++,-3}: Id: {p.Id,-10} " +
$"进程名称: {p.ProcessName,-20} " +
$"完整路径: {p.MainModule.FileName,-40} " +
$"优先级: {p.BasePriority,-10} " +
$"物理内存:{p.WorkingSet64/1024,8}K " +
$"虚拟内存:{p.VirtualMemorySize64 / 1024,8}" +
$"K 进程线程数:{p.Threads.Count,-5}");
}
catch (Exception ex)
{
WriteLine($"{p.ProcessName}:{ex.Message}");
}
}
}
运行这段代码最好先获得较高的系统权限,可以在 app.manifest文件中配置。
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<!-- UAC 清单选项
如果想要更改 Windows 用户帐户控制级别,请使用
以下节点之一替换 requestedExecutionLevel 节点。n
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
指定 requestedExecutionLevel 元素将禁用文件和注册表虚拟化。
如果你的应用程序需要此虚拟化来实现向后兼容性,则删除此
元素。
-->
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
</requestedPrivileges>
否则的话,会有许多进程无法查看详细信息。
我们可以设置进程的PriorityClass属性来为进程指定优先级。如果想结束一个进程的话,可以使用Kill方法。
static void KillProcess(IEnumerable<Process> ps,Process p)
{
if (p == null)
return;
WriteLine($"进程: {p.Id} {p.ProcessName}");
try
{
p.Kill();
}catch(Exception ex)
{
WriteLine("Exception: " + ex.Message);
Process cmd = new Process();
cmd.StartInfo.FileName = "cmd.exe";
cmd.StartInfo.UseShellExecute = false;
cmd.StartInfo.RedirectStandardInput = true;//指示应用程序的输入是否从 System.Diagnostics.Process.StandardInput 流中读取的值
cmd.StartInfo.RedirectStandardOutput = true;
cmd.StartInfo.RedirectStandardError = true;
cmd.StartInfo.CreateNoWindow = true;
cmd.Start();
cmd.StandardInput.WriteLine("ntsd -c q -p "+p.Id);//使用ntsd命令杀掉进程
cmd.StandardInput.WriteLine("Exit");
}
finally
{
DisplayProcess(ps);
}
}
如果该进程没有被顺利的Kill,我们可以使用ntsd命令来强制结束它。这里我们需要创建一个cmd进程,并且对其进行输入重定向,在程序内执行指令,结束某个进程。
启动一个进程相当简单:
Process cmd = new Process();
cmd.StartInfo.FileName = "cmd.exe";
cmd.Start();
可以为StartInfo.FileName指定其他路径的可执行文件
也可以使用Process类的Start静态方法来启动进程,例如:Process.Start(“IExplore.exe”, “www.northwindtraders.com”);
创建守护线程
在明白了上述内容之后,创建守护线程其实很简单。
- 当守护线程运行时,首先根据指定的程序路径,判断该程序是否正在运行
- 如果该程序已经在运行,开启监视线程
- 如果该程序未运行,启动该程序,开启监视线程。
判断该程序是否正在运行:
private void ScanProcessList(string path)
{
Process[] processes = Process.GetProcesses();
foreach (var p in processes)
{
//System、Idle进程会拒绝访问其全路径
try
{
if (this.FormatPath(path) == this.FormatPath(p.MainModule.FileName.ToString()))
{
//进程已启动
this.WatcherProcess(p);
return;
}
}
catch (Exception ex)
{
this.SaveLog("进程:" + p.Id.ToString() +“ ” + p.ProcessName.ToString() +“ ex: ”+ ex.Message);
}
}
//进程尚未启动
SessionApi.CreateProcess(path);
ScanProcessList(path);
}
上面的代码中并没有使用Process的Start()方法来运行程序,因为我这个守护线程的宿主程序是一个Windows服务,在Windows服务中打开交互式程序会存在Session 0隔离,那是一个复杂的问题。Session 0隔离
开启监视线程:
private void WatcherProcess(Process p)
{
Task.Factory.StartNew(() => ResetProcess(p));
}
private void ResetProcess(Process p)
{
try
{
string path = p.MainModule.FileName;
while (true)
{
p.WaitForExit();
p.Close();
SessionApi.CreateProcess(path);
Task.Delay(1000);
}
}
catch (Exception ex)
{
this.SaveLog("RestartProcess() 出错,监控程序已取消对进程("
+ p.Id.ToString() + ")(" + p.ProcessName.ToString()
+ ")的监控,错误描述为:" + ex.Message.ToString());
}
}
WaitForExit()可以阻塞线程,使得Process组件无限期的等待关联进程结束,当它结束后,我们会立刻创建一个新的进程,并继续等待它结束。
边栏推荐
猜你喜欢
随机推荐
学习笔记:2.3 静态链表 循环链表 双向链表
使用fontforge修改字体,只保留数字
phpmyadmin 4.8.1 远程文件包含漏洞(CVE-2018-12613)
Flask 教程 第十章:邮件支持
方舟综合指令代码大全系统综合
Solve the problem of slow speed of gradle import package
1259 Alice and Bob
用固态U盘让你的办公环境随身移动
Yarn 总结(未完待续)
0-1 背包问题
投资基金定投安全吗
IO in Kotlin flow
正则表达式与文本处理器
Factorial of 1088 N
leveldb-impl:level0
解决执行Command报错fork/exec /xxx/yy: no such file or directory
Kotlin delegate property knowledge points
CSP-J2021 题解
Kotlin's JSON format parsing
学习笔记:第二部分 队列