【Windows核心编程学习笔记】用户模式下的线程同步之三---Slim读/写锁(SRWLock)及同步方式比较
一、SRWLock锁的工作原理
SRWLock锁的目的和关键段相同:对一个资源进行保护,不让其他线程访问它。但是,与关键段不同的是:SRWLock锁允许我们区分哪些想要读取资源的值的线程(读取者线程)和想要更新资源的值的线程(写入者线程)。让所有的读取者线程在同一时刻访问共享资源应该是可行的,这是因为读取资源并不存在破坏资源的风险。只有当写入者线程想要对资源进行更新的时候才需要进行同步。在这种情况下:写入者线程独占对资源的访问权。
二、SRWLock锁的用法
首先,需要分配一个SRWLOCK结构并进行初始化:
用户模式下同步机制性能的对比实验结果如下(计数单位:微秒)线程数
Volatile Read
Volatile Write
Interlocked Increment
Critical Section
SRWLock Shared
SRWLock Exclusive
Mutex
1
8
8
35
66
66
67
1060
2
8
76
153
268
134
148
11082
4
9
145
361
768
244
307
23785
各种机制对比:(1)读取volatile长整型值,读取非常快,因为不需要进行任何同步,与CPU的高速缓存完全无关。
(2)写入volatile长整型值。单线程的时间和读取差不多,但是双线程的时候时间不只是加倍,这是因为CPU之间必须相互通信以维护高速缓存的一致性。如果机器有更多的CPU,那么性能还会下降,因为需要在更多的CPU之间进行通信来使得所有CPU的高速缓存一致。
(3)使用InterlockedIncrement来安全递增一个volatile长整型值。
它比第一种方法要慢,这是因为CPU必须锁定内存。使用两个线程要比一个线程慢得多,这是因为必须在两个CPU之间来回传输数据以维护高速缓存的一致性。
(4)使用关键段来读取一个volatile长整型值。
关键段比较慢,是因为我们必须先进入再离开。进入和离开需要修改CRITICAL_SECTION结果中的多个字段。4个线程需要花费更多时间,是因为上下文切换增大了发生争夺现象的可能性。
(5)使用SRWLock来读取一个volatile长整型值。
当有多个线程的时候,读操作比写操作快。由于多个线程会不断地写入锁的字段以及它保护的数据,因此各CPU必须在它们的高速缓存之间来回传输数据。
它的性能和关键段差不多,但是很多时候要优于关键段。建议的做法是用SRWLock替代关键段。
(6)使用同步内核对象互斥量。
互斥量是目前性能最差的,是因为等待互斥量以及后来释放互斥量需要线程每次在用户模式和内核模式之间却换,开销很大。
总结:应该首先尝试不要共享数据,然后依次使用volatile读取、volatile写入、Interlocked函数、SRWLock以及关键段。仅当这些都不能满足要求的时候,再使用内核对象。
实例代码: