《天书夜读:从汇编语言到windows内核编程》十 线程与事件
1)驱动中使用到的线程是系统线程,在system进程中。创建线程API函数:PsCreateSystemThread;结束线程(线程内自行调用)API函数:PsTerminateSystemThread;关闭线程句柄API函数:ZwClose。以下代码忽略同步问题
线程函数:
void MyThreadProc(PVOID context)
{
PUNICODE_STRING str = (PUNICODE_STRING)context;
//打印字符串
KdPrint(("PrintInMyThread:%wZ\r\n",str));
//结束自己
PsTerminateSystemThread(STATUS_SUCCESS);
}
创建线程:
UNICODE_STRING str = RTL_CONSTANT_STRING(L"hello!");
HANDLE hThread = NULL;
NTSTATUS status = PsCreateSystemThread(
&hThread,//新线程句柄
0L,NULL,NULL,NULL,
MyThreadProc,//函数地址
(PVOID)&str//传递参数
);
if ( !NT_SUCCESS(status) )
{
KdPrint(("CreateSystemThread failed!"));
}
ZwClose(hThread);
2) 在线程中睡眠API函数:KeDelayExecutionThread
//时间转换宏,这个是从毫秒转换到百纳秒(负数)
#define DELAY_ONE_MICROSECOND (-10)
#define DELAY_ONE_MILLISECOND (DELAY_ONE_MICROSECOND*1000)
void MySleep(LONG msec)
{
LARGE_INTEGER my_interval;
my_interval.QuadPart = DELAY_ONE_MILLISECOND;
my_interval.QuadPart *= msec;
KeDelayExecutionThread(KernelMode/*不允许报警*/,&my_interval);
}
线程+睡眠函数可以实现定时器功能,但是定时器的回调函数运行在APC中断级别(较Passive中断级别高),有些函数就不能够被中断去执行;而睡眠线程运行在Passive级别,总是可以保证被执行。
3)Sleep函数对线程的延时是不准确的,它的执行原理是在每个轮转到自己的时间片时,判断被延时的时间是否达到,如果没有达到,则放弃当前时间片,这样的话,如果系统在做其它任务而迟迟不将时间片交付给运用程序,那么,延时函数将极度不准确。而对于定时器,是将定时器对象加入到系统队列统一减少“滴答”值来定时,当时间到则系统调用回调函数实现定时器中的工作内容,这是否会有严重延时暂时还不能确定!
4)使用同步事件:事件数据结构是KEVENT,它需要使用KeInitializeEvent函数来初始化,使用KeSetEvet来设置有信号状态,使用KeResetEvent来设置无信号状态,使用KeWaitForSingleObject来等待事件信号。事件不需要销毁。自动重设事件可用于线程互斥,一旦事件被设置为有信号,所有的等待线程中只有一个线程会进入临界区,其它的继续阻塞;而手动重设事件不能用于线程互斥,一旦事件被设置为有信号状态,所有等待该事件的线程都将得到释放,继续执行下面的代码,它可用于同步。
#define DELAY_ONE_MICROSECOND (-10)
#define DELAY_ONE_MILLISECOND (DELAY_ONE_MICROSECOND*1000)
void MySleep(LONG msec)
{
LARGE_INTEGER my_interval;
my_interval.QuadPart = DELAY_ONE_MILLISECOND;
my_interval.QuadPart *= msec;
KeDelayExecutionThread(KernelMode,,&my_interval);
}
void MyThreadProc(PVOID context)
{
PUNICODE_STRING str = (PUNICODE_STRING)context;
//打印字符串
int i;
; i < ; i++)
{
MySleep();
KdPrint(("PrintInMyThread:%wZ\r\n",str));
}
//设置有信号
KeSetEvent(&event,
IO_NO_INCREMENT,//预备给被唤醒线程临时提升优先级的增量
FALSE//之后是否跟KeWaitForXXX等待(其它或者自身)事件
);
//结束自己
PsTerminateSystemThread(STATUS_SUCCESS);
}
测试代码:
//定义一个全局静态事件
static KEVENT event;
//在入口函数写
UNICODE_STRING str = RTL_CONSTANT_STRING(L"hello!");
HANDLE hThread = NULL;
NTSTATUS status;
//事件初始化
KeInitializeEvent(&event,
SynchronizationEvent,//自动复位
FALSE//初始为无信号状态
);
//创建一个线程
status = PsCreateSystemThread(
&hThread,//新线程句柄
0L,NULL,NULL,NULL,
MyThreadProc,//函数地址
(PVOID)&str//传递参数
);
if ( !NT_SUCCESS(status) )
{
KdPrint(("CreateSystemThread failed!"));
}
KdPrint(("Start KeWaitForSingleObject!"));
KeWaitForSingleObject(&event,
Executive,//等待原因,驱动程序设置为Executive
KernelMode,//内核模式
FALSE,//不允许警告
NULL//等待超时时间:无限等待
);
ZwClose(hThread);
KdPrint(("KeWaitForSingleObject return!"));
这种等待线程的返回并不需要使用到线程同步,可用如下函数取代:
//须包含Ntoskrnl.lib
ZwWaitForSingleObject(hThread,
FALSE,//不允许警告
NULL//等待超时时间:无限等待
);
效果图:

《天书夜读:从汇编语言到windows内核编程》十 线程与事件的更多相关文章
- 《天书夜读:从汇编语言到windows内核编程》五 WDM驱动开发环境搭建
(原书)所有内核空间共享,DriverEntery是内核程序入口,在内核程序被加载时,这个函数被调用,加载入的进程为system进程,xp下它的pid是4.内核程序的编写有一定的规则: 不能调用win ...
- 《天书夜读:从汇编语言到windows内核编程》八 文件操作与注册表操作
1)Windows运用程序的文件与注册表操作进入R0层之后,都有对应的内核函数实现.在windows内核中,无论打开的是文件.注册表或者设备,都需要使用InitializeObjectAttribut ...
- 《天书夜读:从汇编语言到windows内核编程》六 驱动、设备、与请求
1)跳入到基础篇的内核编程第7章,驱动入口函数DriverEnter的返回值决定驱动程序是否加载成功,当打算反汇编阅读驱动内核程序时,可寻找该位置. 2)DRIVER_OBJECT下的派遣函数(分发函 ...
- 《天书夜读:从汇编语言到windows内核编程》十一 用C++编写内核程序
---恢复内容开始--- 1) C++的"高级"特性,是它的优点也是它的缺点,微软对于使用C++写内核程序即不推崇也不排斥,使用C++写驱动需注意: a)New等操作符不能直接使用 ...
- 《天书夜读:从汇编语言到windows内核编程》四 windows内核调试环境搭建
1) 基础篇是讲理论的,先跳过去,看不到代码运行的效果要去记代码是一个痛苦的事情.这里先跳入探索篇.其实今天的确也很痛苦,这作者对驱动开发的编译与调试环境介绍得太模糊了,我是各种尝试,对这个环境的搭建 ...
- 《天书夜读:从汇编语言到windows内核编程》九 时间与定时器
1)使用如下自定义函数获取自系统启动后经历的毫秒数:KeQueryTimeIncrement.KeQueryTickCount void MyGetTickCount(PULONG msec) { L ...
- 《天书夜读:从汇编语言到windows内核编程》七 内核字符串与内存
1)驱动中的字符串使用如下结构: typedef struct _UNICODE_STRING{ USHORT Length; //字符串的长度(字节数) USHORT MaximumLength; ...
- 《天书夜读:从汇编语言到windows内核编程》三 练习反汇编C语言程序
1) Debug版本算法反汇编,现有如下3×3矩阵相乘的程序: #define SIZE 3 int MyFunction(int a[SIZE][SIZE],int b[SIZE][SIZE],in ...
- 《天书夜读:从汇编语言到windows内核编程》二 C语言的流程与处理
1) Debug与Release的区别:前者称调试版,后者称发行版.调试版基本不优化,而发行版会经过编译器的极致优化,往往与优化前的高级语言执行流程会大相径庭,但是实现的功能是等价的. 2) 如下fo ...
随机推荐
- Java历程-初学篇 Day02变量,数据类型和运算符
一,数据类型 1,基础数据类型 整型 byte short int long 浮点型 float double 字符型 char 布尔类型 boolean 2,引用类型 String 字符串型 二,变 ...
- Sqlserver数据库 通过表触发器 实时通知应用程序
/* Sqlserver数据库开始相关服务 以下示例显示了如何查看 OLE Automation Procedures 的当前设置.0未启用 */ EXEC sp_configure 'show ad ...
- plsql部分字段中文乱码,sqlplus中文乱码
PLSQL中文乱码 问题: 解决: 思路1:设置 export NLS_LANG="SIMPLIFIED CHINESE_CHINA.ZHS16GBK" 结果:并不能解决问题! ...
- 组件 layui 表单抓取数据四步走
注意事项: layui 中提交按钮是基于"监听"机制实现的. form.on() 的调用需置于 layui.use 的回调函数中. 末尾的 'return false' 不可或缺, ...
- 当谈到 GitLab CI 的时候,我们该聊些什么(上篇)
"微服务"这个概念近两年非常热,正在慢慢改变 DevOps 的思路.微服务架构把一个庞大的业务系统拆解开来,每一个组件变得更加独立自治.松耦合.但是,同时也伴随着部署单元粒度越来越 ...
- 如何抽象一个 Vue 公共组件
之前一直想写一篇关于抽象 Vue 组件的随笔,无奈一直没想到好的例子.恰巧最近为公司项目做了一个数字键盘的组件,于是就以这个为例聊聊如何抽象 Vue 的组件. 先上 Demo 与 源码.(demo最好 ...
- CSS滤镜效果
使用 filter: blur() 生成毛玻璃效果 使用 filter: drop-shadow() 生成整体阴影效果 使用 filter: opacity() 生成透明度 blur生成阴影 通常我们 ...
- 项目总结一:响应式之CSS3 媒体查询
1.<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scala ...
- Kinect v2(Microsoft Kinect for Windows v2 )配置移动电源解决方案
Kinect v2配置移动电源解决方案 Kinect v2如果用于移动机器人上(也可以是其他应用场景),为方便有效地展开后续工作,为其配置移动电源是十分必要的. 一.选择移动电源 Kinect v2原 ...
- python 带小数点时间格式化
#获取带小数点的时间>>> import datetime #当前时间加3天 >>> t1 = datetime.datetime.now() + datetime ...