《天书夜读:从汇编语言到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 ...
随机推荐
- HDU2066 一个人的旅行 最短路基础
新手熟悉一下迪杰斯特拉... 一个人的旅行 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Ot ...
- jdbc-日期格式的转换及代码示例
时间类型相互转换 把数据库的三种时间类型赋给java.util.Date,基本不用转换,因为这是把子类对象给父类的引用,不需要转换. java.sql.Date date = - java.ut ...
- cocos2dx - 节点管理
接上一节内容:cocos2dx - v2.3.3编辑器骨骼动画 本节主要Cocos2dx中节点的管理及应用 一般用法 用过Cocos2dx应该都有用过addChild,removeChild方法.或者 ...
- 吾八哥学Python(二):Python代码编辑器的选用
Python开发环境配置好了,但发现自带的代码编辑器貌似用着有点不大习惯啊,所以咱们就找一个"好用的"代码编辑器吧,网上搜了一下资料,Python常用的编辑器有如下一些: 1. S ...
- canvas图表详解系列(4):动态散点图
本章建议学习时间4小时 学习方式:详细阅读,并手动实现相关代码(如果没有canvas基础,需要先学习前面的canvas基础笔记) 学习目标:此教程将教会大家如何使用canvas绘制各种图表,详细分解步 ...
- Go 单例模式[个人翻译]
原文地址:http://marcio.io/2015/07/singleton-pattern-in-go/ 最近几年go语言的增长速度非常惊人,吸引着各界人士切换到Go语言.最近有很多关于使用Rub ...
- win10 uwp 弹起键盘不隐藏界面元素
本文主要讲,在我们使用手机输入的时候,会因为手机的虚拟键盘隐藏了一些界面的元素.我们有一个简单的方法让虚拟键盘不隐藏界面元素. 我们需要的界面元素是在显示了虚拟键盘后的空间能全部显示,如果不能的话,还 ...
- js金钱转大写
function Arabia_to_Chinese(Num) { // var money=$("#deal_amount").val(); for ( i = Num.leng ...
- python学习之第三课时--基本数据类型及区别,变量
基本数据类型及区别 1. 数字类型(int) 数字型--变量值直接是数字,没有双引号"" 整数 2. 浮点数(float) 肤浅理解小数点后有有效数字 1.55 0.22 ...
- C++运算符重载(10)
编译器在默认情况下为每个类生成一个默认的赋值操作,用于同类的两个对象之间相互赋值.默认的含义是逐个为成员赋值,即将一个对象的成员的值赋给另一个对象相应的成员,这种赋值方式对于有些类可能是不正确的. 运 ...