8 事件等待

devtools/2025/1/13 0:13:18/

临界区&自旋锁

这两个章节在”多核同步“篇已经学习过了,需要了解的可以自行查看对应章节。

线程等待与唤醒

我们在之前的课程里面了解了如何自己实现临界区以及什么是Windows自旋锁,这两种同步方案在线程无法进入临界区时都会让当前线程进入等待状态。

一种是通过Sleep函数实现的,一种是通过让当前的CPU”空转“实现的,但这两种等待方式都有局限性:

  1. 通过Sleep函数进行等待,并没有办法确定具体等待的时间,有可能出现等待过长或过短的情况;

  2. 通过让CPU”空转“进行等待,只有在等待事件很短的情况下才有意义,否则空转时间过长,对CPU资源来说就是一种浪费,并且自旋锁的方式只在多核的环境下存在

我们发现如上所说的两种方案,都是由于等待条件的不成熟,所产生的局限。

等待与唤醒机制

在Windows中,一个线程可以通过等待一个或者多个可等待对象,从而进入等待状态,另一个线程可以在某些时刻唤醒等待这些对象的其他线程,这就是Windows的等待与唤醒机制

images/download/attachments/2424889/image2023-5-15_15-45-45.png

可等待对象

所谓可等待对象就是结构体,如下是一些结构体,我们可以在Windbg中查看这些结构体。

images/download/attachments/2424889/image2023-5-15_17-21-41.png

在Windbg中查看结构体,我们会发现这些结构体的第一个成员都是_DISPATCHER_HEADER,也就表示第一个成员为_DISPATCHER_HEADER的结构体就是可等待对象。

images/download/attachments/2424889/image2023-5-15_17-23-29.png

除了这个以外,在Windows中还有一些特殊的结构体,也称之为可等待对象,如_FILE_OBJECT,我们可以看见该结构体的第一个成员就不是_DISPATCHER_HEADER,但是在它的0x5C偏移位成员有一个_KEVENT结构体,这个结构体是一个可等待对象,因此_FILE_OBJECT也是一个可等待对象。

images/download/attachments/2424889/image2023-5-15_17-26-32.png

因此,综上所述我们可以知道只要结构体中成员有_DISPATCHER_HEADER,或包含了_DISPATCHER_HEADER结构体的,我们都可以称之为可等待对象

差异

虽然以上所述的两种类型结构体都称之为可等待对象,但两者之间也是有差异的。差异在等待函数调用过程中体现出来。

当我们使用WaitForSingleObject函数时,进入内核函数NtWaitForSingleObject,这个内核函数会通过3环用户提供的句柄找到等待对象的内核地址;然后判断等待对象的第一个成员是否是_DISPATCHER_HEADER,如果是的话则直接使用;如果不是的话,则去等待对象中找到嵌入的_DISPATCHER_HEADER对象。最后再将找到的对象地址作为参数调用KeWaitForSingleObject函数,该函数核心功能会在后续章节中学习。

images/download/attachments/2424889/image2023-5-15_17-36-59.png

等待块

一个线程可以等待一个或多个对象,线程与等待对象建立联系主要通过等待块,我们可以做个实验来看一下。

一个线程等待一个对象

首先我们可以在XP中编译这样一段代码,来看一下一个线程等待一个对象的情况:

#include <windows.h>

#include <stdio.h>

HANDLE hEvent[2];

DWORD WINAPI ThreadProc(LPVOID lpParameter)

{

::WaitForSingleObject(hEvent[0], -1);

printf("ThreadProc函数执行...\n");

return 0;

}

int main(int argc, char* argv[])

{

hEvent[0] = ::CreateEvent(NULL, TRUE, FALSE, NULL);

::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc, NULL, 0, NULL);

getchar();

return 0;

}

运行程序之后,在Windbg中断一下,然后通过如下图中的指令找到当前进程中正在等待的线程地址:

images/download/attachments/2424889/image2023-5-16_16-33-2.png

接着我们以线程结构体的方式代入线程地址查看,找到0x5C偏移位成员,即等待块:

images/download/attachments/2424889/image2023-5-16_16-36-7.png

等待块是一个_KWAIT_BLOCK结构体,它将线程与被等待对象联系到了一起,我们接着来看一下它的成员含义:

nt!_KWAIT_BLOCK

+0x000 WaitListEntry : _LIST_ENTRY // 稍后了解

+0x008 Thread : Ptr32 _KTHREAD // 当前线程地址

+0x00c Object : Ptr32 Void // 等待对象的地址(当前实验中为_KEVENT)

+0x010 NextWaitBlock : Ptr32 _KWAIT_BLOCK // 下一个等待块地址,这是一个单向循环链表,存储的是与当前线程关联的多个等待块结构体地址,如果只有一个等待块则该地址指向当前等待快地址

+0x014 WaitKey : Uint2B // 等待块的索引,当前为第一个等待块,因此该值为0

+0x016 WaitType : Uint2B // 等待类型,若当前只要有一个等待对象符合条件就可以使得线程被唤醒,那么该值就是1;如果你等待多个对象必须全部符合条件才可以使得线程被唤醒,那么该值0

images/download/attachments/2424889/image2023-5-16_16-37-23.png

综上所述,我们可以使用如下图来表示一个线程等待一个对象的情况:

images/download/attachments/2424889/image2023-5-16_16-43-26.png

一个线程等待多个对象

一个线程等待多个对象的情况,我们需要将代码进行修改,如下代码所示,我们添加两个可等待对象,然后将WaitForSingleObject替换为WaitForMultipleObjects,这样就可以使得一个线程等待多个对象。

值得注意的是,WaitForMultipleObjects函数多出了两个参数,分别是第一个参数nCount(即等待对象的数量)第二个参数bWaitAll


http://www.ppmy.cn/devtools/150005.html

相关文章

使用Python实现智能交通违章检测系统

友友们好! 我的新专栏《Python进阶》正式启动啦!这是一个专为那些渴望提升Python技能的朋友们量身打造的专栏,无论你是已经有一定基础的开发者,还是希望深入挖掘Python潜力的爱好者,这里都将是你不可错过的宝藏。 在这个专栏中,你将会找到: ● 深入解析:每一篇文章都将…

krpano 实现文字热点中的三角形和竖杆

krpano 实现文字热点中的三角形和竖杆 实现文字热点中的三角形和竖杆 一个后端写前端真的是脑阔疼 一个后端写前端真的是脑阔疼 一个后端写前端真的是脑阔疼 实现文字热点中的三角形和竖杆 上图看效果 v&#xff1a;2549789059

【github】向右箭头文件打不开,下载也是空白

从输出来看&#xff0c;你已经 暂存&#xff08;staged&#xff09;了删除 src 文件夹的操作&#xff0c;但在同一时间&#xff0c;你在本地重新创建了一个新的 src/ 文件夹&#xff08;未被追踪的文件&#xff09;。 你需要解决这两种状态的冲突&#xff08;已删除和未追踪的…

ASP.NET Core 实现微服务 - Elastic APM

这次要给大家介绍的是Elastic APM &#xff0c;一款应用程序性能监控组件。APM 监控围绕对应用、服务、容器的健康监控&#xff0c;对接口的调用链、性能进行监控。在我们实施微服务后&#xff0c;由于复杂的业务逻辑&#xff0c;服务之间的调用会像蜘蛛网一样复杂。有了调用链…

外观模式详解与应用

外观模式&#xff08;Facade Pattern&#xff09;&#xff0c;也称为门面模式&#xff0c;是一种结构型设计模式。它提供了一个统一的接口来访问子系统中的一组接口&#xff0c;从而简化了高层模块对子系统的使用。通过外观模式&#xff0c;可以将复杂的子系统封装起来&#xf…

HTML5 渐变动画(Gradient Animation)

HTML5 渐变动画&#xff08;Gradient Animation&#xff09; 渐变动画是一种动态效果&#xff0c;通过改变元素的背景颜色或其他属性来实现渐变变化。以下是如何使用 CSS 和 HTML5 创建渐变动画的详细说明。 1. 基本概念 渐变动画&#xff1a;通过在不同颜色之间平滑过渡来创…

windows安装wsl

安装Windows Subsystem for Linux (WSL)&#xff1a; • 打开PowerShell并运行以下命令安装WSL&#xff1a; wsl --install Windows PowerShell 版权所有 © Microsoft Corporation。保留所有权利。 尝试新的跨平台 PowerShell https://aka.ms/pscore6 PS C:\Users\Admi…

P7012 [CERC2013] Draughts

网址如下&#xff1a; P7012 [CERC2013] Draughts - 洛谷 | 计算机科学教育新生态 有点坑了&#xff0c;白棋不止一个&#xff0c;而题目说“你会得到一个白棋的位置” 总的来说就是dfs硬做 代码如下&#xff1a; #include<cstdio> #include<cstring> #include&…