浅析 C# Console 控制台为什么也会卡死
一:背景
1. 讲故事
在分析旅程中,总会有几例控制台的意外卡死导致的生产事故,有经验的朋友都知道,控制台卡死一般是动了 快速编辑窗口
的缘故,截图如下:
虽然知道缘由,但一直没有时间探究底层原理,市面上也没有对这块的底层原理介绍,昨天花了点时间简单探究了下,算是记录分享吧。
二:几个疑问解答
1. 界面为什么会卡死
相信有很多朋友会有这么一个疑问?控制台程序明明没有 message loop
机制,为什么还能响应 窗口事件 呢?
说实话这是一个好问题,其实 Console 之所以能响应 窗口事件,是因为它开了一个配套的 conhost 窗口子进程,用它来承接 UI 事件,为了方便阐述,上一段定时向控制台输出的测试代码。
static void Main(string[] args){for (int i = 0; i < int.MaxValue; i++){Console.WriteLine($"i={i}");Thread.Sleep(1000);}}
将程序跑起来,再用 process explorer 观察进程树即可。
接下来用 windbg 附加到 conshost 进程上,观察下有没有 GetMessageW
。
0:005> ~* k0 Id: 3ec8.2c20 Suspend: 1 Teb: 000000d2`92014000 Unfrozen# Child-SP RetAddr Call Site
00 000000d2`922ff798 00007fff`a3e45746 ntdll!NtWaitForSingleObject+0x14
01 000000d2`922ff7a0 00007fff`a60b5bf1 KERNELBASE!DeviceIoControl+0x86
02 000000d2`922ff810 00007ff6`9087a790 KERNEL32!DeviceIoControlImplementation+0x81
03 000000d2`922ff860 00007fff`a60b7614 conhost!ConsoleIoThread+0xd0
04 000000d2`922ff9e0 00007fff`a66a26a1 KERNEL32!BaseThreadInitThunk+0x14
05 000000d2`922ffa10 00000000`00000000 ntdll!RtlUserThreadStart+0x21
...2 Id: 3ec8.1b70 Suspend: 1 Teb: 000000d2`9201c000 Unfrozen# Child-SP RetAddr Call Site
00 000000d2`9227f858 00007fff`a4891b9e win32u!NtUserGetMessage+0x14
01 000000d2`9227f860 00007ff6`908735c5 user32!GetMessageW+0x2e
02 000000d2`9227f8c0 00007fff`a60b7614 conhost!ConsoleInputThreadProcWin32+0x75
03 000000d2`9227f920 00007fff`a66a26a1 KERNEL32!BaseThreadInitThunk+0x14
04 000000d2`9227f950 00000000`00000000 ntdll!RtlUserThreadStart+0x21
...
2. 进程间如何通讯
这个问题再细化一点就是Client 端通过 Console.WriteLine($"i={i}");
写入的内容是如何被 Server 端的conhost!ConsoleIoThread
方法接收到的。
熟悉 Windows 编程的朋友都知道:Console.WriteLine 的底层调用逻辑是 ntdll!NtWriteFile -> nt!IopSynchronousServiceTail
,前者是用户态进入到内核态的网关函数,后者是用户将irp丢到线程的请求包队列后进入休眠(KeWaitForSingleObject),直到驱动提取并处理完之后唤醒。
说了这么多,怎么去验证呢?
- 客户端下断点
0: kd> !process 0 0 ConsoleApp2.exe
PROCESS ffffe001b5e51840SessionId: 1 Cid: 0e8c Peb: 7ff7ab226000 ParentCid: 09d4DirBase: 18079000 ObjectTable: ffffc00036965200 HandleCount: <Data Not Accessible>Image: ConsoleApp2.exe0: kd> bp /p ffffe001b5e51840 nt!IopSynchronousServiceTail
0: kd> g
Breakpoint 0 hit
nt!IopSynchronousServiceTail:
fffff802`a94f3410 48895c2420 mov qword ptr [rsp+20h],rbx
3: kd> k# Child-SP RetAddr Call Site
00 ffffd000`f6477988 fffff802`a94f2e80 nt!IopSynchronousServiceTail
01 ffffd000`f6477990 fffff802`a916db63 nt!NtWriteFile+0x680
02 ffffd000`f6477a90 00007ffc`2fed38aa nt!KiSystemServiceCopyEnd+0x13
03 0000009f`0743dbd8 00007ffc`2cd1d478 ntdll!NtWriteFile+0xa
04 0000009f`0743dbe0 00000000`00000005 0x00007ffc`2cd1d478
05 0000009f`0743dbe8 0000009f`0743dcf0 0x5
06 0000009f`0743dbf0 0000009f`0978c9b8 0x0000009f`0743dcf0
07 0000009f`0743dbf8 00007ffc`2986e442 0x0000009f`0978c9b8
08 0000009f`0743dc00 0000009f`0743dc30 0x00007ffc`2986e442
09 0000009f`0743dc08 0000009f`0743de00 0x0000009f`0743dc30
0a 0000009f`0743dc10 00000000`00000005 0x0000009f`0743de00
0b 0000009f`0743dc18 00000000`00000000 0x53: kd> tc
nt!IopSynchronousServiceTail+0x70:
fffff802`a94f3480 e8ebf1b5ff call nt!IopQueueThreadIrp (fffff802`a9052670)
- 服务端下断点
conhost端的提取逻辑是在 conhost!ConsoleIoThread
方法中,它的内部调用的是 kernelbase!DeviceIoControl
函数,这个方法挺有意思,可以直接给驱动程序下达命令,方法签名如下:
BOOL DeviceIoControl(HANDLE hDevice,DWORD dwIoControlCode,LPVOID lpInBuffer,DWORD nInBufferSize,LPVOID lpOutBuffer,DWORD nOutBufferSize,LPDWORD lpBytesReturned,LPOVERLAPPED lpOverlapped
);
提取完了之后会通过 conhost!DoWriteConsole
向控制台输出,接下来可以下个断点验证下。
0:000> bp conhost!DoWriteConsole
0:000> g
Breakpoint 0 hit
conhost!DoWriteConsole:
00007ff6`90876ec0 48895c2410 mov qword ptr [rsp+10h],rbx ss:00000095`d627f738=0000000000000000
0:000> r
rax=000000000000000c rbx=00000095d627f7b0 rcx=000002370df76cc0
rdx=00000095d627f768 rsi=00000095d627f7c0 rdi=00000095d627f7f0
rip=00007ff690876ec0 rsp=00000095d627f728 rbp=00000095d627f8f9r8=000002370bedf010 r9=00000095d627f7b0 r10=000002370df76cc0
r11=000002370e0c9d00 r12=00000095d627f970 r13=000002370bedf010
r14=000002370bedf010 r15=0000000000000000
iopl=0 nv up ei pl zr na po nc
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
conhost!DoWriteConsole:
00007ff6`90876ec0 48895c2410 mov qword ptr [rsp+10h],rbx ss:00000095`d627f738=0000000000000000
0:000> du 000002370df76cc0
00000237`0df76cc0 "i=18.."
可以看到果然有一个 i=18
,这里要提醒一下,要想看方法的顺序逻辑,可以借助 perfview。
3. 为什么快捷编辑之后就卡死
conhost 的源码不是公开的,不过可以感官上推测出来。
-
快速编辑窗口 被用户启用后, GetMessage 会感知到这个自定义的 MSG 消息。
-
这个消息的逻辑会让 server 处理Client消息的流程一直处于等待中,导致 Client 的 IopSynchronousServiceTail 不能被唤醒,导致一直处于阻塞中,类似 Task 的完成状态一直不被设置。
接下来可以验证下 快速编辑窗口
的处理消息码是多少,只要在控制台点一下鼠标。参考脚本如下:
0:004> bp win32u!NtUserGetMessage "dp ebp-30 L2 ; g"
0:004> g
00000095`d61ffae0 00000000`00130e6e 00000000`00000404
00000095`d61ffae0 00000000`00130e6e 00000000`00000404
00000095`d61ffae0 00000000`00130e6e 00000000`00000201
00000095`d61ffae0 00000000`00130e6e 00000000`00000405
00000095`d61ffae0 00000000`00130e6e 00000000`00000202
00000095`d61ffae0 00000000`00130e6e 00000000`00000200
从 chaggpt 中对每个消息码的介绍,可以看到会有一个 405 的自定义消息,这个就是和 快速编辑窗口
有关的。
三:总结
这篇就是我个人对窗口卡死的推测和记录,高级调试不易,如果大家感兴趣,欢迎补充细节。
相关文章:

浅析 C# Console 控制台为什么也会卡死
一:背景 1. 讲故事 在分析旅程中,总会有几例控制台的意外卡死导致的生产事故,有经验的朋友都知道,控制台卡死一般是动了 快速编辑窗口 的缘故,截图如下: 虽然知道缘由,但一直没有时间探究底层…...

zookeeper详解
一 zookeeper介绍 首先需要了解zookeeper是什么,zookeeper是一个分布式协调服务。所谓分布式协调主要是来解决分布式系统中多个进程之间的同步限制,防止出现脏读,例如我们常说的分布式锁。 zookeeper中的数据是存储在内存当中的,因…...

达索智能制造解决方案,敏捷电芯制造如何赋能企业竞争力 | 百世慧®
敏捷电芯制造赋能企业竞争力 全球电池市场正在快速扩大,为制造商带来巨大商机。 锂电行业的智能制造如何应用? 电池制造业的市场趋势是什么? 电池制造商面临哪些挑战? 特别是电池电芯制造方面,如何克服挑战获得竞…...
自然语言处理---迁移学习实践
1 微调脚本介绍 指定任务类型的微调脚本: huggingface研究机构提供了针对GLUE数据集合任务类型的微调脚本, 这些微调脚本的核心都是微调模型的最后一个全连接层。通过简单的参数配置来指定GLUE中存在任务类型(如: CoLA对应文本二分类,MRPC对应句子对文本二分类&…...

看得懂的——数据库中的“除”操作
通过一个例子来解释数据库中的“除”操作 R➗S其实就是判断关系R中X各个值的象集Y是否包含关系S中属性Y的所有值 求解步骤 第一步 找出关系R和关系S中相同的属性,即Y属性。在关系S中对Y做投影(即将Y列取出);所得结果如下&#x…...

el-input无法输入的问题和表单验证失败问题(亲测有效)-开发bug总结4
大部分无法输入的问题:基本都是没有进行v-model双向数据绑定,这个很好解决。 本人项目中遇到的bug问题如下: 点击添加,表单内可输入用户名 和 用户姓名,但有时会偶发出现无法这两个input框里面无法输入内容。 原因&a…...

OpenCV+QT实现的数字图像处理算法合集
源码下载地址: 基于OpenCV和QT的图像处理源码 图像预处理 灰度处理 灰度直方图 灰度均衡 梯度锐化 Laplace锐化 边缘检测 Roberts Sobel Laplace Prewitt canny Krisch 噪声 椒盐噪声 高斯噪声 滤波 均值滤波 中值滤波 双边滤波 形态学滤波 高斯滤波 图像变…...

想要查看员工与客户聊天记录和跟进情况,有什么工具推荐吗?
想要查看员工与客户 聊天记录和跟进情况 有什么工具推荐吗? 想要查看员工与客户聊天记录和每天新增客户,可以使用微信管理系统这个工具。 微信管理系统是一个能够同时登录多个微信,实现一个人管理多个微信的工具。它分为两大版块,…...
androdi知识笔记
jbr embed:android studio自带的jdk AGP(android gradle plugin) aar jar 利用java语言可以写应用程序(利用已有库加速开发过程),也可以自己开发库用于特定功能(供引用)。 循环啊是个࿰…...

华为数通方向HCIP-DataCom H12-831题库(多选题:21-40)
第21题 网络管理员A希望使用ACL匹配特定的路由条目,请问以下哪些路由条目将被图中的ACL规侧匹配? acl number 2000 rule 10 permit source 10.0.0.0 0.0.6.0A、10.0.0.1/32 B、10.0.0.0/24 C、10.0.1.0/24 D、10.0.2.0/24 答案: 解析: 通配符十进制6转换二进制为00000110,…...

数据要素安全流通:挑战与解决方案
文章目录 数据要素安全流通:挑战与解决方案一、引言二、数据要素安全流通的挑战数据泄露风险数据隐私保护数据跨境流动监管 三、解决方案加强数据安全防护措施实施数据隐私保护技术建立合规的数据跨境流动机制 四、数据安全流通的未来趋势01 数据价值与产业崛起02 多…...
【Mybatis源码】XMLConfigBuilder构建器 - 加载XML与创建Configuration对象的过程
XMLConfigBuilder是Mybatis中定义的进行构建Configuration对象的类,此类用于读取XML配置文件创建并初始化Configuration对象;本篇我们主要介绍加载XML文件与创建Configuration对象的过程。 一、Configuration对象的创建过程 下面是从Configuration类中取到的代码片段: pu…...

台灯显色指数多少好?推荐显色指数优秀的护眼台灯
台灯的显色指数是其非常重要的指标,它可以表示灯光照射到物体身上,物体颜色的真实程度,一般用平均显色指数Ra来表示,Ra值越高,灯光显色能力越强。常见的台灯显色指数最低要求一般是在Ra80以上即可,比较好的…...

【2024秋招】2023-8-5-小红书-数据引擎团队后端开发提前批面经
1 面试官介绍 OLAP引擎,离线引擎,大数据分析中间件 2 自我介绍 缺点: (1)面试官让重点介绍自己最在行的项目,我真的在自我介绍上扯了一些别的东西… (2)在面试的时候因为想看简…...

【Docker从入门到入土 4】使用Harbor搭建Docker私有仓库
私有仓库 一、Harbor简介1.1 什么是Harbor?1.2 Harbor的特性1.3 Harbor和docker registry的关系1.4 Harbor的构成1.4 Harbor 配置文件中的两类参数1.4.1 所需参数1.4.2 可选参数 二、Harbor部署2.1 部署Docker-Compose服务2.2 部署 Harbor 服务Step1 下载或上传 Harbor 安装程…...
监控易一体化运维:打造机房环境监控的卓越典范
随着信息技术的飞速发展,机房作为企业数据和业务的中心,其运行状态和管理的重要性日益凸显。为确保机房的稳定性和可靠性,越来越多的企业选择使用一体化运维管理软件来进行实时监控。在这方面,监控易品牌提供了一款全面而高效的机…...
【X3m】DDR压力测试
Index of /downloads/unittest/ 设置CPU模式和降频温度# 若设备重启需再次配置这两条指令 echo performance > /sys/devices/system/cpu/cpufreq/policy0/scaling_governor echo 105000 > /sys/devices/virtual/thermal/thermal_zone0/trip_point_1_temp #1 cpu test ec…...

【Linux】32条指令带你玩转 Linux !
目录 1,whoami 2,who 3,pwd 4,ls 1,ls 2,ls -l 3,ls -a 4,ls -al 5,ls -d 6,ls -ld 5,clear 6,cd 1,cd 2&…...

高效恢复丢失的文件的10 款Android数据恢复工具
在当今快节奏的数字时代,从Android设备丢失重要数据可能是一场噩梦。 您需要一个可靠的恢复工具来取回您的数据,例如令人难忘的照片,重要的联系人,重要的工作文档等。 值得庆幸的是,有许多高效的Android数据恢复工具可…...

Python数据挖掘 | 升级版自动查核酸
📕作者简介:热爱跑步的恒川,致力于C/C、Java、Python等多编程语言,热爱跑步,喜爱音乐的一位博主。 📗本文收录于恒川的日常汇报系列,大家有兴趣的可以看一看 📘相关专栏C语言初阶、C…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...

高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...

华为OD机考-机房布局
import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseSystem.out.println(solve(in.nextLine()));}}priv…...

【网络安全】开源系统getshell漏洞挖掘
审计过程: 在入口文件admin/index.php中: 用户可以通过m,c,a等参数控制加载的文件和方法,在app/system/entrance.php中存在重点代码: 当M_TYPE system并且M_MODULE include时,会设置常量PATH_OWN_FILE为PATH_APP.M_T…...
比较数据迁移后MySQL数据库和OceanBase数据仓库中的表
设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...

华为OD机试-最短木板长度-二分法(A卷,100分)
此题是一个最大化最小值的典型例题, 因为搜索范围是有界的,上界最大木板长度补充的全部木料长度,下界最小木板长度; 即left0,right10^6; 我们可以设置一个候选值x(mid),将木板的长度全部都补充到x,如果成功…...

9-Oracle 23 ai Vector Search 特性 知识准备
很多小伙伴是不是参加了 免费认证课程(限时至2025/5/15) Oracle AI Vector Search 1Z0-184-25考试,都顺利拿到certified了没。 各行各业的AI 大模型的到来,传统的数据库中的SQL还能不能打,结构化和非结构的话数据如何和…...
TCP/IP 网络编程 | 服务端 客户端的封装
设计模式 文章目录 设计模式一、socket.h 接口(interface)二、socket.cpp 实现(implementation)三、server.cpp 使用封装(main 函数)四、client.cpp 使用封装(main 函数)五、退出方法…...

链式法则中 复合函数的推导路径 多变量“信息传递路径”
非常好,我们将之前关于偏导数链式法则中不能“约掉”偏导符号的问题,统一使用 二重复合函数: z f ( u ( x , y ) , v ( x , y ) ) \boxed{z f(u(x,y),\ v(x,y))} zf(u(x,y), v(x,y)) 来全面说明。我们会展示其全微分形式(偏导…...