在看到 Win10 或 Win11 的 Task Manager 任务管理器时,不知大家是否有一个疑问,在 进程 标签里的应用进程是如何分组的。为什么有些组能包含很多个不同的进程,有些只能包含一个。本文将使用 WPF 写一个简单的应用来告诉大家任务管理器的进程分组策略

如下图,这是任务管理器看到的 VisualStudio 的界面,可以看到这个进程组里面包含很多个进程

那任务管理器将这些进程放在一个组里面的依据是什么?我能否可以将我自己的进程放在一个组里面,或者反过来我不想让我的进程放在一个组里面

在开始之前,需要说明的是,当前的任务管理器是不开源的,我也没有找到权威的文档来说这个事情,问了微软的大佬们,也没有收到回复。因此本文只能说是基于测试的结果了解任务管理器的行为。要是微软想不开,改了行为,那本文给出的分组策略也许就不对

任务管理器的分组依据是:

前台进程所直接启动的后台进程,将会放入到此前台进程所在的组里面

这里的前台进程指的是应用里面可以看到的进程,也是有带主窗口且显示的进程

前台进程所直接启动的后台进程的逻辑含义是此前台进程和对应的后台进程有父子进程关系

而后台进程指的是没有前台主窗口的进程,和是否控制台应用没有很大的关系,如果是控制台应用且有前台控制台窗口主机,依然不会被加入组内。或者说控制台应用存在前台主窗口,也不会被加入组内。也就是说只取决于是否存在前台主窗口,和是否控制台应用没有本质关系,即使是没有主窗口 GUI 应用,在这里也被当成后台进程

后台进程和前台进程之间是可以转换的,当前台进程没有前台主窗口时将转换为后台进程,当后台进程有前台主窗口时将转换为前台进程

另外继承链上的父子孙关系情况下,情况有些复杂,能否将孙进程显示在一个进程组里面,取决于子进程的存活时间,如果子进程在启动孙进程之后很快就退出,那么孙进程将不会被计入组里。如果子进程在启动孙进程之后,没有很快退出,那么孙进程将会被计入组里

以上的策略是我通过测试了解的,接下来将告诉大家这个测试应用的代码是如何编写的

先测试 前台进程所直接启动的后台进程,将会放入到此前台进程所在的组里面 的情况。测试方法就是通过一个带前台主窗口进程,启动另一个没有带前台主窗口的进程,看看在任务管理器里面是否放在一个组里面

新建一个叫 HakewofuCayorejar 的 WPF 应用,本文的代码基于 .NET 7 编写

为了方便代码编写,这里启动的多个进程都是相同的一个应用,只不过通过命令行参数决定不同的行为。为了更好的控制应用的逻辑,这里删除了 App.xaml 和 App.xaml.cs 文件,更改为自己编写 Main 函数

添加 Program 类,代码如下,用来在没有传入参数的时候,显示 MainWindow 作为前台主窗口。如果有命令行参数,那就啥都不做

static class Program
{
[STAThread]
static void Main(string[] args)
{
var application = new Application()
{
ShutdownMode = ShutdownMode.OnExplicitShutdown
};
application.Startup += (sender, eventArgs) =>
{
if (args.Length == 0)
{
var mainWindow = new MainWindow();
mainWindow.Show();
}
else
{
}
};
application.Run();
}
}

在 MainWindow 放一个按钮,点击按钮的时候,启动进程,传入参数

    private void Button_OnClick(object sender, RoutedEventArgs e)
{
var file = System.IO.Path.GetFullPath("HakewofuCayorejar.exe");
Process.Start(file, "xxxxx");
}

运行代码,然后点击按钮,接着看任务管理器,可以看到任务管理器里面的 HakewofuCayorejar 组将随着按钮的点击,可以看到越来越多的进程

再接着,关闭 HakewofuCayorejar 的 MainWindow 窗口,可以看到在任务管理器里面的应用刷新了,找不到 HakewofuCayorejar 组。只有在任务管理器的后台进程才能找到 HakewofuCayorejar 进程,这就证明了 HakewofuCayorejar 在关闭前台主窗口之后,从原本的前台进程转换为后台进程

再编辑一下代码测试任务管理器的更多行为,测试当一个后台进程转换为前台进程时的任务管理器行为情况,更改以上代码的 Program 代码,让带参数的进程等待几秒之后显示主窗口


static class Program
{
[STAThread]
static void Main(string[] args)
{
var application = new Application()
{
ShutdownMode = ShutdownMode.OnExplicitShutdown
};
application.Startup += (sender, eventArgs) =>
{
if (args.Length == 0)
{
var mainWindow = new MainWindow();
mainWindow.Show();
}
else
{
application.Dispatcher.InvokeAsync(async () =>
{
await Task.Delay(5000);
var mainWindow = new MainWindow();
mainWindow.Show();
});
}
};
application.Run();
}
}

运行代码,点击按钮,可以看到开始是将新的 HakewofuCayorejar 进程放入到第一个 HakewofuCayorejar 进程的组里面。但是等待一会,就可以看到任务管理器刷新了界面,拆开为两个 HakewofuCayorejar 组。这就证明了后台进程是可以通过显示前台主窗口转换为前台进程

接着测试父子孙进程的情况,测试孙进程是否被加入任务管理器的组里,取决于子进程在启动孙进程进程之后还能存在多久

更改 Program 的代码如下

static class Program
{
[STAThread]
static void Main(string[] args)
{
var application = new Application()
{
ShutdownMode = ShutdownMode.OnExplicitShutdown
};
application.Startup += async (sender, eventArgs) =>
{
if (args.Length == 0)
{
var mainWindow = new MainWindow();
mainWindow.Show();
}
else if (args.Length == 1)
{
var file = System.IO.Path.GetFullPath("HakewofuCayorejar.exe");
Process.Start(file, "xxxxx xxxxx");
await Task.Delay(10);
application.Shutdown();
}
};
application.Run();
}
}

让子进程使用两个参数启动孙进程,然后延迟 10 毫秒再退出

运行应用,不断点击按钮,让子进程启动孙进程。通过任务管理器可以看到,任务管理器的组里面有多少个进程,完全看任务管理器的心情或者说子进程的退出延迟。偶尔孙进程加入到组里面,偶尔孙进程没有加入组里面

本文的代码放在 githubgitee 欢迎访问

可以通过如下方式获取本文的源代码,先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码

git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin af83d991a8bc603d64501d27e8cf511b3cefbf81

以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继续输入以下代码

git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
git pull origin af83d991a8bc603d64501d27e8cf511b3cefbf81

获取代码之后,进入 HakewofuCayorejar 文件夹

WPF 探索任务管理器的进程分组逻辑的更多相关文章

  1. wpf 异常处理和关闭进程

    using System; using System.Collections.Generic; using System.Configuration; using System.Data; using ...

  2. C# 保护进程不被结束(源代码)防任务管理器结束进程

    C# 保护进程不被结束(源代码)防任务管理器结束进程 Posted on 2013-03-25 16:03 快乐家++ 阅读(3173) 评论(3) 编辑 收藏 闲来无事,英语又学的太痛苦.看到我妈妈 ...

  3. 理解WPF中的视觉树和逻辑树

    轉載地址:http://blog.csdn.net/changtianshuiyue/article/details/26981797 理解WPF中的视觉树和逻辑树  Understanding th ...

  4. WPF筛选、排序和分组

    可以通过CollectionViewSource或者CollectionView对视图进行排序.筛选和分组. 一.通过CollectionViewSource listingDataView是Coll ...

  5. 【windows】windows系统下,在任务管理器的进程选项卡中查看PID/任务管理器怎么查看PID

    PID,就是windows上的进程ID,是一个进程的唯一标识值. 那今天启动JDK跑起来一个项目之后,想要在任务管理器中查看这个JDK所在进程的PID但是看不到. 怎么解决? 1.我在任务管理器的服务 ...

  6. WPF知识点全攻略06- WPF逻辑树(Logical Tree)和可视树(Visual Tree)

    介绍概念之前,先来分析一段代码: xaml代码如下: <Window x:Class="WpfApp1.MainWindow" xmlns="http://sche ...

  7. Windows Server 2008 R2服务器内存使用率过高,但与任务管理器中进程占用内存和不一致

    系统环境: Windows Server 2008 R2 + Sql Server 2008 R2   问题描述: Windows Server 2008 R2系统内存占用率过大,而在任务管理器中各进 ...

  8. C#/WPF 仅启动一个进程实例

    如何实现仅启动一个 WPF 进程实例,并在打开第二个时,自动唤起之前打开的进程. 1 代码入口 在 App.xaml.cs 文件中,重写 OnStartup 方法,并添加 Mutex 进程锁. /// ...

  9. Nginx(二): worker 进程处理逻辑-流程框架

    Nginx 启动起来之后,会有几个进程运行:1. master 进程接收用户命令并做出响应; 2. worker 进程负责处理各网络事件,并同时接收来自master的处理协调命令: master 主要 ...

  10. C#程序双击运行之后,界面不显示,但是在任务管理器有进程(一个winform找bug之旅)

    最近客户端又出了奇葩事情:http://q.cnblogs.com/q/43038/ 如这篇博问一样.我的一个客户的电脑上程序打开了,进程也有了,就是界面窗体出不来!!! 我是win7是开发机,三四台 ...

随机推荐

  1. C#的窗体防闪烁解决方案 - 开源研究系列文章

    昨天编码的时候想到了关于无边框窗体的闪烁问题,主要是改变窗体大小的时候会闪烁,默认的窗体没这个问题.而现在无边框窗体的应用比较多,所以就找了度娘,然后结合自己的经验进行了测试,得到了这个例子,简单有效 ...

  2. 记录--用Echarts打造自己的天气预报!

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 前言 最近刚刚学习了Echarts的使用,于是想做一个小案例来巩固一下.项目效果如下图所示: 话不多说,开始进入实战. 创建项目 这里我们 ...

  3. [Java]静态代理、动态代理(基于JDK1.8)

    [版权声明]未经博主同意,谢绝转载!(请尊重原创,博主保留追究权) https://www.cnblogs.com/cnb-yuchen/p/18002823 出自[进步*于辰的博客] 参考笔记一,P ...

  4. 英语文档阅读之Zynq-7000 All Programmable SoC

    Read "Zynq-7000 All programmable Soc" 1.Table of Contents 首先是目录,可以看到是标准的总分结构.开头介绍了Zynq的各种功 ...

  5. 【已解决】mybatis注解@Param失效,无法获取到值(org.apache.ibatis.binding.BindingException: Parameter 'policy' not found. Available parameters are [arg1, arg0, param1, param2])

    案发现场: 传递的参数是一个实体类 PolicyDictionary 此时我无法拿到数据: 解决思路一(不推荐) 删去@Param注解,使用mybatis默认的参数顺序: 不使用@param注解传递多 ...

  6. Python---json数据格式详解

    什么是JSON JSON是一种取代XML的数据结构,和xml相比,它更小巧但描述能力却不差,由于它的小巧所以网络传输数据将减少更多流量从而加快速度. 那么,JSON到底是什么? JSON就是一串字符串 ...

  7. Linux中JMeter的使用

    Linux中JMeter的使用 Linux版本JMeter安装 # 1.下载.安装JMeter 如果有安装包直接上传即可 wget -c https://archive.apache.org/dist ...

  8. Git 删除 .gitignore 生成之前上传的文件

    清除缓存 git rm -r --cached . git add . 提交记录 git commit -m "chore: 清除缓存." git push

  9. C++ 运算符全解析:从基础概念到实际应用

    C++ 运算符 运算符用于对变量和值执行操作. 在下面的示例中,我们使用 + 运算符将两个值相加: int x = 100 + 50; 虽然 + 运算符经常用于将两个值相加,就像上面的示例一样,但它也 ...

  10. Java 构造函数与修饰符详解:初始化对象与控制权限

    Java 构造函数 Java 构造函数 是一种特殊的类方法,用于在创建对象时初始化对象的属性.它与类名相同,并且没有返回值类型. 构造函数的作用: 为对象的属性设置初始值 执行必要的初始化操作 提供创 ...