c++ - 释放锁时的线程调度
问题描述
我在解锁互斥锁时的期望是调度程序检查当前尝试锁定该互斥锁的其他线程,然后执行其中一个等待线程。我编写了一个测试程序(见下面的代码),其中有 2 个线程都试图在一个循环中获取相同的互斥锁并做一些工作(睡眠 1 毫秒)。不同之处在于一个线程t1
在解锁和尝试重新获取互斥锁之间等待片刻,而另一个线程t2
则不会。我期待两个线程获取互斥锁的次数大致相同。但是,在 windows 上,t1
通常只获取一次互斥锁,而其他线程则获取数百次。在 linux 上,行为是不同的,两个线程都完成了t2
大约两倍的工作。为什么t1
在 Windows 上几乎从不获取互斥锁?我该如何修改代码才能做到这一点?
示例代码:
#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 文档上阅读有关超薄读取器/写入器锁的更多信息:Slim Reader/Writer (SRW) Locks
Joe Duffy 还在博客中讨论了公平与锁护卫问题:Windows Server 2003 SP1 和 Windows Vista 中的反护卫锁
推荐阅读
- openshift - 将 Spring Cloud Data Flow 2.6.0 部署到 Openshift
- amazon-web-services - HashiCorp Vault 在 EC2 之外无法访问
- javascript - 在 chrome 扩展中使用 declarativeContent API
- java - 尝试使用 Firebase 实时数据库 setValue() 时出现权限被拒绝错误
- java - flink中,如何多次遍历Iterable对象?
- javascript - 具有多个参数的 Firebase onCall 函数
- javascript - 无法使用ajax从数据库中调用php删除
- python - 仅使用 Beautiful Soup 获取外部 html 部分
- mongodb - 优化大型索引对象的 MongoDB 聚合查询
- python - 如何防止 % 符号忽略以下 2 个字符