Windows驱动开发(11) - 驱动程序的同步处理(二)

Windows驱动开发(11) - 驱动程序的同步处理(二)

3、自旋锁

自旋锁也是一种同步机制,它能保证某个资源只能被一个线程所拥有,这种保护被形象地称做“上锁”。

3.1 原理

  在Windows内核中,有一种被称为自旋锁(Spin Lock)的锁,它可以用于驱动程序中的同步处理。初始化自旋锁时,处理解锁状态,这时它可以被程序“获取”。“获取”后的自旋锁处理于锁定状态,不能再被“获取”。如果自旋锁已被锁住,这时有程序申请“获取”这个锁,程序则处于“自旋”状态。所谓自旋状态,就是不停地询问是否可以“获取”自旋锁。
  自旋锁不同于线程中的等待事件,在线程中如果等待某个事件(Event),操作系统会使这个线程进入休眠状态,CPU会运行其他线程;而自旋锁原理则不同,它不会切换到别的线程,而是一直让这个线程“自旋”。因此对自旋锁占用时间不宜过长,否则会导致申请自旋锁的其他线程处于自旋,会浪费CPU时间。
  驱动程序必须在低于或者等于DISPATCH_LEVEL的IRQL级别中使用自旋锁。

3.2 使用方法

  自旋锁的作用是为使各派遣函数之间同步,尽量不要将自旋锁放在全局变量中,而应该将自旋锁放在设备扩展中。
  自旋锁用KSPIN_LOCK数据结构表示。

typedef struct _DEVICE_EXTENSION  
{  
    .....  
    KSPIN_LOCK My_SpinLock; // 在设备扩展中定义自旋锁  
}DEVICE_EXTENSION, *PDEVICE_EXTENSION;  

  使用自旋锁首先需要对其进行初始化,可以使用KeInitializeSpinLock内核函数。一般是在驱动程序的DriverEntry或AddDevice函数中初始化自旋锁。
  申请自旋锁可以使用内核函数KeAcquireSpinLock,它有两个参数,一个为自旋锁指针,第二个参数记录获得自旋锁以前的IRQL级别。

PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;  
KIRQL oldirql;  
KeACquireSpinLock(&pdx->My_SpinLock, &oldirql);  

4、用户模式下的同步对象

4.1 用户模式下的信号灯

  信号灯也是一种常见的同步对象,信号灯也有两种状态,一种是激发状态,另一种是未激发状态。信号灯内部有个计数器,可以理解信号灯内部有N个灯泡。
  如果有一个灯泡亮着,就代表信号灯处于激发状态,如果全部熄灭,则代表信号灯处于未激发状态。使用信号灯前需要先创建信号灯,CreateSemaphore函数负责创建信号灯。它的声明如下:

HANDLE CreateSemaphoreA(  
    IN LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, // 安全属性  
    IN LONG lInitialCount,                          // 初始化计数个数  
    IN LONG lMaximumCount,                          // 计数器最大个数  
    IN LPCSTR lpName                                // 命名  
    );  

  其中,第二个参数lInitialCount在指明初始化时,计数器的值为多少。
  第三个参数lMaximumCount指明该信号灯计数器的最大值是多少。如果初始值为0,则处于未激发状态;如果初始值为非零,则处于激发状态。
  另外,可以使用期ReleaseSemaphore函数增加信号灯的计数器,其函数声明如下:

BOOL ReleaseSemaphore(  
    IN HANDLE hSemaphore,  
    IN LONG lReleaseCount,  
    OUT LPLONG lpPreviousCount  
    );  

其中,第二个参数lReleaseCount是这次操作增加计数的数量;
第三个参数lpPreviousCount获得执行本操作之前计数的大小。
另外,对信号灯执行一次等待操作,就会减少一个计数,相当于熄灭一个灯泡。当计数为零时,也就是所有灯泡都熄灭时,当前线程进入睡眠状态,直到信号灯变为激发状态。
下面综合以上API,缩写了信号灯同步对象的使用方法:

5、内核模式下的同步对象

6、其他同步方法

你可能感兴趣的:(Win驱动开发,windows,驱动开发,内核)