《Windows内核编程》---系统线程和同步事件
系统线程:
在驱动中生成的线程一般是系统线程,系统线程所在的进程名为“System”,用到的内核API函数是:
NTSTATUS PsCreateSystemThread(
OUT PHANDLE ThreadHandle,
IN ULONG DesiredAccess,
IN POBJECT_ATTRIBUTES objectAttributes OPTIONAL,
IN HANDLE ProcessHandle OPTIONAL,
OUT PCLIENT_ID ClientId OPTIONAL,
IN PKSTART_ROUTINE StartRoutine,
IN PVOID StartContext
);
一般情况下,ThreadHandle用来返回句柄,放入一个句柄指针即可;DesiredAccess赋值为0;接着三个可选参数都赋值为0;StartRoutine参数是用于该线程启动时执行的函数;StartContext是线程函数的参数。线程函数的原型如下:
VOID CustomThreadProc(IN PVOID context); //context自然就是由上面的StartContext传入的
注意:线程在结束时应该自己调用PsTerminateSystemThread函数来完成,此外得到的线程句柄ThreadHandle要使用ZwClose来关闭。(关闭句柄并不等于结束线程)
下面的函数演示怎样创建并使用系统线程:
//线程函数
VOID ASCEThreadProc(PVOID context)
{
PUNICODE_STRING str = (PUNICODE_STRING)context;
//打印字符串
KdPrint((“Print In ASCEThead:%wZ/r/n”, str));
//结束自己
PsTerminateSystemThread(STATUS_SUCCESS);
}
VOID ASCEFunction()
{
UNICODE_STRING str = RTL_CONSTANT_STRING(L”ASCE!”);
HANDLE thread = NULL;
NTSTATUS status;
status = PsCreateSystemThread(
&thread, 0L, NULL, NULL, NULL, ASCEThreadProc, (PVOID)&str);
if(!NT_SUCCESS(status))
{
//错误处理
…-.
}
//成功了,则做自己的事
…-..
//最后关闭句柄
ZwClose(thread);
}
上面代码存在如下错误:ASCEThreadProc执行时,ASCEFunction可能已经执行完了。而执行完之后,堆栈中的str就无效了。此时再执行KdPrint打印str一定会蓝屏。
合理的方法是在堆中分配str的空间,或者str必须在全局空间中。当然,我们也可以在PsCreateSystemThread结束之后,在它的后面加上一个等待线程结束的语句。
在线程中睡眠:
在驱动编程中使用到的用于睡眠的内核函数是:
NTSTATUE KeDelayExecutionThread(
IN KPROCESSOR_MODE WaitMode,
IN BOOLEAN Alertable,
IN PLARGE_INTEGER Interval
);
其中参数WaitMode应该总是赋值为KernelMode,因为我们现在是在内核编程;Alertable表示是否允许线程报警(用于重新唤醒);Interval表示要睡眠多长时间。
下面是简单的睡眠函数,它可以指定睡眠多少毫秒:
#define DELAY_ONE_MICROSECOND (-10)
#define DELAY_ONE_MILLISECOND (DELAY_ONE_MICROSECOND*1000)
VOID ASCESleep(LONG msec)
{
LARGE_INTEGER asceInterval;
asceInterval.QuadPart = DELAY_ONE_MILLISECOND;
asceInterval.QuadPart *= msec;
KeDelayExecutionThread(KernelMode, 0, &asceInterval);
}
同步对象:
内核中的事件是一个数据结构,这个结构的指针可以当作一个参数传入一个等待函数中。如果这个事件不被“设置”,则这个等待函数不会返回,这个线程被阻塞;如果这个事件被“设置”,则等待结束,线程可以继续执行。
如果一个线程需要等待另一个线程完成某事之后才能做某事,则可以使用事件等待。这个数据结构就是KEVENT,这个结构总是用KeInitializeEvent初始化:
VOID KeInitializeEvent(
IN PRKEVENT Event,
IN EVENT_TYPE Type,
IN BOOLEAN State
);
参数Event是要初始化的事件;Type是事件类型;参数State是初始化状态,一般设置为FALSE,也就是未设置状态,这样等待线程需要等待。注意,事件不需要销毁。
设置事件使用函数KeSetEvent:
LONG KeSetEvent(
IN PRKEVENT Event, //要设置的事件
IN KPRIORITY Increment, //用于提升优先权,可设为0
IN BOOLEAN Wait//表示函数后面是否紧接着一个KeWaitSingleObject来等待这个事件,
//一般设置为TRUE(事件初始化后,一般就要开始等待了)
);
使用事件的简单代码如下:
//等待一个事件
KEVENT event;
//事件初始化
KeInitializeEvent(&event, SynchronizationEvent, TRUE);
…-…-
//事件初始化之后就可以使用了,在一个函数中,我们可以等待某个事件
//如果这个事件没有被人设置,那就会阻塞在这里继续等待
KeWaitForSingleObject(&event, Executive, KernelMode, 0, 0);
…-..
//在另一个函数或其他地方,设置了这个事件。而一旦设置了这个事件
//前面等待的地方就会开始继续执行
KeSetEvent(&event);
上面代码中KeInitializeEvent中使用了SynchronizationEvent,导致这个事件成为所谓的“自动重设”事件。一个事件如果被设置,那么所有KeWaitForSingleObject等待这个事件的地方都会通过。如果要继续重复使用这个事件,必须重设这个事件。当KeInitializeEvent第二个参数设置为NotificationEvent时,这个事件必须要手动重设才能使用。手动重设使用函数:
LONG KeResetEvent(
IN PRKEVENT Event
);
上面代码中的事件初始化为SynchronizationEvent事件,因此只有一个线程的KeWaitForSingleObject可以通过,通过之后被自动重设,其他的线程只能继续等待,这就是一个同步事件。
不能起到同步作用的是通知事件(NotificationEvent),注意,不能用手工设置通知事件的方式来取代同步事件,Don’t be stupid, ok?
下面使用同步事件来改进上面系统线程中的例子,即在线程中打印结束之后,设置同步事件,外面的函数再返回:
static KEVENT asceEvent;
//线程函数
VOID ASCEThreadProc(PVOID context)
{
PUNICODE_STRING str = (PUNICODE_STRING)context;
KdPrint(("Print in ASCEThread: %wZ/r/n", str));
KeSetEvent(&asceEvent); //设置事件
PsTerminateSystemThread(STATUS_SUCCESS);
}
//生成线程的函数
VOID ASCEFunction()
{
UNICODE_STRING str = RTL_CONSTANT_STRING(L"SEE YOU IN ANOTHER LIFE BROTHER");
HANDLE thread = NULL;
NTSTATUS status;
KeInitializeEvent(&asceEvent, SynchronizationEvent, TRUE); //初始化事件
status = PsCreateSystemThread(
&thread, 0L, NULL, NULL, NULL, ASCEThreadProc, (PVOID)&str);
if(!NT_SUCCESS(status))
{
//错误处理
}
ZwClose(thread);
//等待事件结束在返回
KeWaitForSingleObject(&asceEvent, Executive, KernelMode, 0, 0);
}
注意,等待线程结束不一定要用事件,线程本身也可以用来等待。上面函数的缺点是不能起到并发执行的作用。
jpg 改 rar 
《Windows内核编程》---系统线程和同步事件的更多相关文章
- Windows驱动开发之线程与同步事件
转载请注明来源: enjoy5512的博客 : http://blog.csdn.net/enjoy5512 GitHub : https://github.com/whu-enjoy .1. 使用系 ...
- Java并发编程:线程的同步
Java并发编程:线程的同步 */--> code {color: #FF0000} pre.src {background-color: #002b36; color: #839496;} J ...
- 《天书夜读:从汇编语言到windows内核编程》十 线程与事件
1)驱动中使用到的线程是系统线程,在system进程中.创建线程API函数:PsCreateSystemThread:结束线程(线程内自行调用)API函数:PsTerminateSystemThrea ...
- [7] Windows内核情景分析---线程同步
基于同步对象的等待.唤醒机制: 一个线程可以等待一个对象或多个对象而进入等待状态(也叫睡眠状态),另一个线程可以触发那个等待对象,唤醒在那个对象上等待的所有线程. 一个线程可以等待一个对象或多个对象, ...
- 《天书夜读:从汇编语言到windows内核编程》六 驱动、设备、与请求
1)跳入到基础篇的内核编程第7章,驱动入口函数DriverEnter的返回值决定驱动程序是否加载成功,当打算反汇编阅读驱动内核程序时,可寻找该位置. 2)DRIVER_OBJECT下的派遣函数(分发函 ...
- windows内核编程之常用数据结构
1.返回状态 绝大部分的内核api返回值都是一个返回状态,也就是一个错误代码.这个类型为NTSTATUS.我们自己写的函数也大部分这样做. NTSTATUS MyFunction() { NTSTAT ...
- 《天书夜读:从汇编语言到windows内核编程》八 文件操作与注册表操作
1)Windows运用程序的文件与注册表操作进入R0层之后,都有对应的内核函数实现.在windows内核中,无论打开的是文件.注册表或者设备,都需要使用InitializeObjectAttribut ...
- 《天书夜读:从汇编语言到windows内核编程》五 WDM驱动开发环境搭建
(原书)所有内核空间共享,DriverEntery是内核程序入口,在内核程序被加载时,这个函数被调用,加载入的进程为system进程,xp下它的pid是4.内核程序的编写有一定的规则: 不能调用win ...
- Monad、Actor与并发编程--基于线程与基于事件的并发编程之争
将线程.事件.状态等包装成流的源. 核心:解决线程的消耗和锁的效率问题. Java和Node.js可以说分别是基于线程和基于事件的两个并发编程代表,它们互相指责瞧不起对方,让我们看看各种阵营的声音: ...
随机推荐
- Spring Data Commons 官方文档学习
Spring Data Commons 官方文档学习 -by LarryZeal Version 1.12.6.Release, 2017-07-27 为知笔记版本在这里,带格式. Table o ...
- CSS之float vs position:absolute
补充:ul 应该设置下 list-style: none; 题外话:看了张鑫旭的视频,这家伙把简单的css玩出了新花样,绝对大神级的存在.膜拜下先~ float的作用前面一章已经说过了,但没考虑过的是 ...
- 2016年第七届蓝桥杯C/C++B组省赛题目解析
题目1:煤球数目 有一堆煤球,堆成三角棱锥形.具体:第一层放1个,第二层3个(排列成三角形),第三层6个(排列成三角形),第四层10个(排列成三角形),....如果一共有100层,共有多少个煤球?请填 ...
- 第三百八十九节,Django+Xadmin打造上线标准的在线教育平台—列表筛选结合分页
第三百八十九节,Django+Xadmin打造上线标准的在线教育平台—列表筛选结合分页 根据用户的筛选条件来结合分页 实现原理就是,当用户点击一个筛选条件时,通过get请求方式传参将筛选的id或者值, ...
- MySQL 先按某字段分组,再取每组中前N条记录
按 gpcode每组 取每组 f4 最大的那条记录: 方法一: select * from calcgsdataflash a where gscode = 'LS_F' and ymd >= ...
- e828. 创建JTabbedPane
A tabbed pane is a container that displays only one child component at a time. Typically, the childr ...
- 一个 JAR 文件可以用于
用于发布和使用类库 作为应用程序和扩展的构建单元 作为组件.applet 或者插件程序的部署单位 用于打包与组件相关联的辅助资源 package Com.Table; import java.util ...
- Android 4.4从图库选择图片,获取图片路径并裁剪
转至 http://blog.csdn.net/tempersitu/article/details/20557383 最近在做一个从图库选择图片或拍照,然后裁剪的功能.本来是没问题的,一直在用 In ...
- linux stat命令参数及用法详解
功能说明:显示inode内容.语 法:stat [文件或目录]补充说明:stat以文字的格式来显示inode的内容. ls 命令及其许多参数提供了一些非常有用的文件信息.另一个不太为人所熟知的命令 s ...
- Linux网卡eth0变成eth1修改方法
由于换了主板,集成网卡mac地址变了,70-persistent-net.rules中仍然保留了老网卡的内容,新网卡则被识别为eth1. 将表示老网卡的行注释掉,然后将表示新网卡的行中eth1改成et ...