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//等待超时时间:无限等待 );
效果图: