解锁互斥体时,我的期望是调度程序检查当前尝试锁定该互斥体的其他线程,然后执行这些等待线程之一。我编写了一个测试程序(参见下面的代码),其中有 2 个线程都试图在循环中获取相同的互斥体并执行一些工作(休眠 1 毫秒)。不同之处在于,一个线程 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;
}
最佳答案
在 Windows 上,std::mutex
是使用细长的读取器/写入器锁来实现的。此锁实现是不公平的(意味着它不保证等待线程获取锁的顺序)。 Windows 不久前就放弃了公平锁,因为 Microsoft 认为锁保护是比线程饥饿更严重的问题。
您可以在 Microsoft 文档中阅读有关 slim 读取器/写入器锁的更多信息:Slim Reader/Writer (SRW) Locks
Joe Duffy 还在博客中讨论了公平性与锁定车队问题:Anti-convoy locks in Windows Server 2003 SP1 and Windows Vista
关于c++ - 释放锁时的线程调度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53434834/