解锁互斥锁时,我的期望是调度程序检查当前尝试锁定此互斥锁的其他线程,然后执行这些等待的线程之一。我编写了一个具有2个线程的测试程序(请参见下面的代码),这两个线程都试图在一个循环中获取相同的互斥体并做一些工作(休眠1ms)。区别在于,一个线程t1
在解锁和尝试重新获取互斥锁之间等待一会儿,而另一个线程t2
则没有。我期望两个线程获取互斥体的次数大约相同。但是,在Windows t1
上通常仅一次获得互斥,而其他线程则数百次。在Linux上,行为是不同的,两个线程使用t2
完成工作的次数大约是原来的两倍。为什么Windows上的t1
几乎从不获取互斥体?我该如何修改代码才能做到?
示例代码:
#include <iostream>
#include <thread>
#include <mutex>
#include <atomic>
using namespace std;
int main()
{
mutex m;
atomic<bool> go(false);
int t1Counter = 0, t2Counter = 0;
thread t1([&] {
while(!go);
while(go) {
this_thread::sleep_for(100us);
lock_guard<mutex> lg(m);
this_thread::sleep_for(1ms);
++t1Counter;
}
});
thread t2([&] {
while(!go);
while(go) {
lock_guard<mutex> lg(m);
this_thread::sleep_for(1ms);
++t2Counter;
}
});
go = true;
this_thread::sleep_for(1s);
go = false;
t1.join();
t2.join();
cout << t1Counter << " " << t2Counter << endl;
}
答案 0 :(得分:3)
在Windows上,std::mutex
是使用细长的读取器/写入器锁实现的。此锁实现不公平(这意味着它不保证等待线程将获得锁的顺序)。由于微软认为锁护具比线程匮乏更为严重,Windows早已摆脱了公平锁。
您可以阅读有关Microsoft文档上的细长型读写器锁的更多信息:Slim Reader/Writer (SRW) Locks
乔·达菲(Joe Duffy)还写了关于公平与锁定车队问题的博客:Anti-convoy locks in Windows Server 2003 SP1 and Windows Vista