Windows 为什么slim读写器独占锁的性能优于共享锁?
我已经通过C/C++测试了Windows7下slim读写器锁的性能 结果让我惊讶的是,独占锁定性能比共享锁定性能好。下面是代码和结果Windows 为什么slim读写器独占锁的性能优于共享锁?,windows,multithreading,Windows,Multithreading,我已经通过C/C++测试了Windows7下slim读写器锁的性能 结果让我惊讶的是,独占锁定性能比共享锁定性能好。下面是代码和结果 unsigned int __stdcall slim_reader_writer_exclusive(void *arg) { //SRWLOCK srwLock; //InitializeSRWLock(&srwLock); for (int i = 0; i < 1000000; ++i) { Acqu
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;
}
unsigned int\uu stdcall slim\u reader\u writer\u exclusive(void*arg)
{
//SRWLOCK-SRWLOCK;
//初始化srwLock(&srwLock);
对于(int i=0;i<1000000;++i){
AcquireSRWLockExclusive(&srwLock);
g_值=0;
ReleaseSRWLockExclusive(&srwLock);
}
_endthreadex(0);
返回0;
}
未签名整数\uu stdcall slim\u读写器\u共享(void*arg)
{
int b;
对于(int i=0;i<1000000;++i){
获取SRWLockShared(&srwLock);
//b=g_值;
g_值=0;
释放srwlockshared(&srwLock);
}
_endthreadex(0);
返回0;
}
g_值
是一个全局int可变变量
你能解释一下为什么会发生这种情况吗 猜测:
独占锁是更简单的情况。共享锁支持并行性,但需要处理饥饿的可能性,因此会产生额外的开销。对于小型通用锁(如SRWLock,大小只有一个指针),这是一个非常常见的结果 密钥提取:如果您有一个非常小的受保护代码段,因此锁本身的开销可能占主导地位,那么使用独占锁比使用共享锁更好 此外,陈雷蒙关于g_值争论的论点也是正确的。如果在这两种情况下都读取而不是写入g_值,您可能会注意到共享锁的好处 详细信息: SRW锁是使用一个指针大小的原子变量实现的,该变量可以根据低位的值呈现多种不同的状态。关于这些位的使用方式的描述超出了本评论的范围——状态转换的数量相当高——因此,我将仅提及您在测试中可能遇到的几个状态 初始锁定状态:(0,控制位:0)--SRW锁定从所有位设置为0开始 共享状态:(ShareCount:n,ControlBits:1)--当没有冲突的独占获取且锁被共享时,共享计数直接存储在lock变量中 独占状态:(ShareCount:0,ControlBits:1)--当没有冲突的共享获取或独占获取时,锁的位设置为低位,没有其他设置 示例争用状态:(WaitPtr:ptr,ControlBits:3)--当发生冲突时,等待锁的线程使用在等待线程堆栈上分配的数据形成队列。lock变量存储指向队列尾部的指针,而不是共享计数 在这个方案中,当您不知道初始状态是对锁字的单次写入时,尝试获取独占锁,以设置低位并检索旧值(这可以在x86上通过lock BTS指令完成)。如果成功(在1线程的情况下总是这样),则可以继续进入锁定区域,无需进一步操作 尝试获取共享锁是一个更复杂的操作:首先需要读取lock变量的初始值以确定旧的共享计数,增加读取的共享计数,然后使用lock CMPXCHG指令有条件地写回更新后的值。这是一个明显较长的串行相关指令链,因此速度较慢。此外,CMPXCGH在许多处理器上比LOCK BTS等无条件原子指令慢一点 理论上,通过假设锁在开始时处于初始状态并首先执行锁CMPXCHG,可以加速锁的第一次共享获取。这将加快锁的初始共享获取(所有这些都在单线程情况下),但它将大大降低锁已被共享且发生第二次共享获取的情况
释放锁时会发生一组类似的不同操作,因此管理共享状态的额外成本也由ReleaseSrockShared端支付。一位致力于优化Windows中锁的Windows内核开发人员告诉我,性能是一条经验法则:
所以是的,除非读>>>>写,否则最好使用CS。你测试了多少个线程实例?@djna:结果显示,我已经测试了1,2,4个线程。在一个线程的情况下,
42ms
和50ms
之间的差异对我来说似乎是一个合理的抖动-增加样本数量以获得更精确的结果詹德沃夏克:对不起,我找不到你。您的意思是互斥锁1的结果是错误的吗?共享锁在g_值上有争用。独占锁不存在。由于锁不公平,独占版本允许一个线程运行多次迭代(始终保留g_值的所有权)。共享版本强制g_值
的所有权在核心之间不断反弹。