为什么超薄读写器独占锁定优于共享?

时间:2012-11-03 05:49:34

标签: windows multithreading

我使用来自 Windows Via C / C ++ 的代码在Windows 7下测试了瘦读取器/写入器锁的性能。

结果让我感到惊讶的是,独家锁定了共享的性能。这是代码和结果。

unsigned int __stdcall slim_reader_writer_exclusive(void *arg)
{
    //SRWLOCK srwLock;
    //InitializeSRWLock(&srwLock);

    for (int i = 0; i < 1000000; ++i) {
        AcquireSRWLockExclusive(&srwLock);
        g_value = 0;
        ReleaseSRWLockExclusive(&srwLock);
    }
    _endthreadex(0);
    return 0;
}

unsigned int __stdcall slim_reader_writer_shared(void *arg)
{

    int b;
    for (int i = 0; i < 1000000; ++i) {
        AcquireSRWLockShared(&srwLock);
        //b = g_value;
        g_value = 0;
        ReleaseSRWLockShared(&srwLock);
    }
    _endthreadex(0);
    return 0;
}

g_value是一个全局int volatile变量。

enter image description here

您能否解释为何会发生这种情况?

3 个答案:

答案 0 :(得分:19)

对于小型通用锁(如SRWLocks,它只是一个指针大小),这是一个非常常见的结果。

关键点:如果你有一个非常小的保护代码部分,这样锁本身的开销可能占主导地位,那么使用独占锁比使用共享锁更好。

此外,Raymond Chen关于g_Value争论的论点也是正确的。如果在两种情况下都读取了g_Value而不是写入,那么您可能会注意到共享锁的好处。

<强>详细信息:

SRW锁使用单个指针大小的原子变量实现,该变量可以采用多种不同的状态,具体取决于低位的值。这些位的使用方式的描述超出了这个注释的范围 - 状态转换的数量非常高 - 所以,我只提到你在测试中可能遇到的一些状态。

初始锁定状态:(0,ControlBits:0) - SRW锁定以所有位设置为0开始。

共享状态:(ShareCount:n,ControlBits:1) - 当没有冲突的独占获取且锁保持共享时,共享计数直接存储在锁变量中。 / p>

独占状态:(ShareCount:0,ControlBits:1) - 当没有冲突的共享获取或独占获取时,锁定的位设置为低,没有别的。

示例争用状态:(WaitPtr:ptr,ControlBits:3) - 当发生冲突时,等待锁定的线程使用在等待线程上分配的数据形成队列栈。 lock变量存储指向队列尾部的指针,而不是共享计数。

在这个方案中,当你不知道初始状态时尝试获取一个独占锁是对锁定字的单次写入,设置低位并检索旧值(这可以在x86上用一个LOCK BTS指令)。如果你成功了(正如你在1线程案例中所做的那样),你就可以进入锁定区域而不需要进一步的操作。

尝试获取共享锁是一个更复杂的操作:您需要首先读取锁变量的初始值以确定旧的共享计数,增加您读取的共享计数,然后有条件地写回更新的值LOCK CMPXCHG指令。这是一个明显更长的串行相关指令链,因此速度较慢。 CMPXCGH在许多处理器上比LOCK BTS等无条件原子指令慢一点。

理论上可以通过假设锁在开始时处于初始状态并首先执行LOCK CMPXCHG来加速锁的第一次共享获取。这将加速锁的初始共享获取(所有这些都在您的单线程情况下),但它会显着减慢锁已经共享并发生第二次共享获取的情况。

当释放锁时会发生类似的一组不同操作,因此管理共享状态的额外成本也会在ReleaseSRWLockShared端支付。

答案 1 :(得分:4)

致力于优化Windows锁定的Windows内核开发人员告诉我关于性能的经验:

  1. 在大多数情况下使用关键部分以获得最佳性能
  2. 如果您阅读至少4:1与写作
  3. ,请考虑使用SRW锁定
  4. 如果您的代码绝对不允许饥饿,则只使用互斥锁
  5. 显然,人们应该考虑锁的其他方面:

    1. 您必须清理CS,而不必清理SRW锁
    2. CS锁定可以递归,而SRW锁定不能
    3. 互斥锁可以同步UM和KM,如果你在KM,CS和SRW锁定不是真正的选择
    4. 所以是的,只是赞成CS除非读取&gt;&gt;&gt;&gt;写入。

答案 2 :(得分:0)

猜测:

独占锁是更简单的情况。共享锁启用并行性,但需要处理饥饿的可能性,因此会产生额外的开销。