驱动开发(12)内核中的多线程和同步对象

来源:互联网 发布:linux怎么创建目录 编辑:程序博客网 时间:2024/05/22 06:55

本博文由CSDN博主zuishikonghuan所作,版权归zuishikonghuan所有,转载请注明出处:http://blog.csdn.net/zuishikonghuan/article/details/51301896

在内核模式下创建线程

在驱动程序中创建线程的方法是调用 PsCreateSystemThread 内核函数,此函数即可以创建系统线程,也可以创建用户线程。此函数的原型如下:

NTSTATUS PsCreateSystemThread(  _Out_     PHANDLE            ThreadHandle,  _In_      ULONG              DesiredAccess,  _In_opt_  POBJECT_ATTRIBUTES ObjectAttributes,  _In_opt_  HANDLE             ProcessHandle,  _Out_opt_ PCLIENT_ID         ClientId,  _In_      PKSTART_ROUTINE    StartRoutine,  _In_opt_  PVOID              StartContext);
  1. 参数1:一个 HANDLE 类型的指针,用于输出创建的线程句柄。此句柄必须在不需要使用时通过 ZwClose 释放。
  2. 参数2:创建线程的权限,一般设置为0。
  3. 参数3:指向指定对象的属性的结构,一般设置为 NULL 。
  4. 参数4:如果为 NULL ,则线程属于系统。如果指定一个进程句柄,则线程属于该进程,通过 NtCurrentProcess 宏可以得到当前进程句柄。
  5. 参数5:用于接收客户端ID,一般为 NULL 。
  6. 参数6:线程的启动函数指针。
  7. 参数7:传递给启动函数的数据。

线程启动函数原型:

KSTART_ROUTINE ThreadStart;VOID ThreadStart(  _In_ PVOID StartContext){ ... }

需要注意,和用户模式线程不同,线程必须调用 PsTerminateSystemThread (或系统关机)才会退出,而不是函数返回即退出。

内核模式下的等待

驱动程序进行等待可以通过 KeWaitForSingleObject 和 KeWaitForMultipleObjects 进行等待,其实用户模式下的 WaitForSingleObject 和 WaitForMultipleObjects 就是调用了这两个函数,先来看看函数原型:

NTSTATUS KeWaitForSingleObject(  _In_     PVOID           Object,  _In_     KWAIT_REASON    WaitReason,  _In_     KPROCESSOR_MODE WaitMode,  _In_     BOOLEAN         Alertable,  _In_opt_ PLARGE_INTEGER  Timeout);NTSTATUS  KeWaitForMultipleObjects(  _In_      ULONG           Count,  _In_      PVOID           Object[],  _In_      WAIT_TYPE       WaitType,  _In_      KWAIT_REASON    WaitReason,  _In_      KPROCESSOR_MODE WaitMode,  _In_      BOOLEAN         Alertable,  _In_opt_  PLARGE_INTEGER  Timeout,  _Out_opt_ PKWAIT_BLOCK    WaitBlockArray);

解释一下 KeWaitForSingleObject :

  1. 参数1:同步对象的指针。(不是句柄)
  2. 参数2:指定等待的原因。驱动程序应将该值设置为 Executive ,除非是做代表用户的工作,并在用户线程的上下文中,在这种情况下,应该将该值设置为运行 UserRequest 。
  3. 参数3:说明是在内核模式等待还是在用户模式等待(KernelMode or UserMode)一般设置为 KernelMode 。
  4. 参数4:设置等待是否“警惕”,一般为 FALSE 。
  5. 参数5:超时时间,若为 NULL ,则为无限等待(还记得上一篇中说过 IRQL 不小于 DISPATCH_LEVEL 的线程不能进行没有超时的等待操作吗)指向64位整数指针时,若是正数,则为从 January 1, 1601 ,若为负数,则从现在开始计时。

内核模式下的同步对象

和用户模式下的同步对象大致一样,因为用户模式同步对象就是通过调用内核同步对象函数创建的。

在应用程序中我们只能得到同步对象的指针,而在驱动程序中我们可以直接使用事件对象的指针!

对于各函数我想我不必一个个解释了,MSDN说的很清楚了,这里只起一个引导和区分作用。

1。事件

创建事件:KeInitializeEvent

创建命名事件:IoCreateNotificationEvent 和 IoCreateSynchronizationEvent

命名的事件对象的好处是,可以方便在不同驱动中找到事件对象的指针。

NotificationEvent(通知事件)和 SynchronizationEvent(同步事件)的区别:前者由未激发变为激发时,需要手动变成未激发,而后者激发后调用 KeWaitFor… 函数就会自动变为未激发。

2。自旋锁

获取自旋锁:KeAcquireSpinLock

释放自旋锁:KeReleaseSpinLock

自旋锁有“锁住”和“解锁”状态,当线程获取自旋锁时,如果处于解锁状态就可以被获取,获取会自动锁住自旋锁,必须释放后才能解锁;如果获取时处于锁住状态,那么线程就会不停地“自旋”,即线程不停地常数获取自旋锁,直到获取到为止。自旋锁不能工作在 IRQL DISPATCH_LEVEL 中断请求级。

特别需要注意:线程如果等待一个“事件”对象,那么线程就会休眠,操作系统会去调度其他线程,而获取自旋锁不同,线程会一直“自旋”,会浪费宝贵的 CPU 时间,因此获取自旋锁后到释放之前的时间不要过长。

3。互斥体/快速互斥体

创建互斥体:KeInitializeMutex

释放互斥体:KeReleaseMutex

创建快速互斥体:ExInitializeFastMutex

释放快速互斥体:ExReleaseFastMutex

快速互斥体不能被线程递归获取。

只有一个线程可以占用互斥体,获取互斥体的线程如果不释放互斥体,其他线程就不能得到互斥体,线程获取到一个互斥体时,互斥体变为激发,释放一个互斥体时,互斥体变为未激发。互斥体未激发时,等待互斥体就可以获取他,激发时则会使线程休眠,直到指定互斥体被释放后,才会有且仅有一个等待该互斥体的线程获取该互斥体。

4。信号量

创建信号量:KeInitializeSemaphore

释放信号量: KeReleaseSemaphore

信号量同样有激发和未激发两种状态,他的特殊之处是内部维护一个计数器,只要计数器不小于1就是激发状态,否则是未激发状态。

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 老年人门牙掉了怎么办 老年人磨牙掉了怎么办 种植牙牙龈发炎怎么办 种植牙牙龈红肿怎么办 种植牙后牙龈怎么办 种植牙牙龈感染怎么办 种植牙牙龈向上怎么办 上门牙有点突出怎么办 电脑语音电流声怎么办 麦克风说不了话怎么办 耳机说不了话怎么办 饿了么小休超时怎么办 美团清退代理商怎么办 小孩龟头肿很大怎么办 16岁不想上学怎么办 宜宾南门桥逆行怎么办 去加拿大探亲签证怎么办 重庆两路口到菜坝园怎么办 摄像头uid忘了怎么办 电梯钢丝绳断了怎么办 在小区车被砸了怎么办 甲米天气下雨怎么办 电影院不开空调怎么办 电脑总弹广告怎么办 下雨天了怎么办神接 天下雨了怎么办套路 下雨天了怎么办 新套路 万达兑换券过期怎么办 直播间没一个人怎么办 快手直播人少怎么办 快手直播人气少怎么办 被火山主播踢出房间怎么办 遇到同事的排挤怎么办 交警处理事故不公平怎么办 派出所处理事情不公平怎么办 淘宝号不健康了怎么办 作业盒子忘记密码怎么办 一起作业忘记密码怎么办 手机不能录视频怎么办 网络机顶盒连不上wifi怎么办 obs游戏源黑屏怎么办