首页 > 解决方案 > 释放锁时的线程调度

问题描述

我在解锁互斥锁时的期望是调度程序检查当前尝试锁定该互斥锁的其他线程,然后执行其中一个等待线程。我编写了一个测试程序(见下面的代码),其中有 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;
}

标签: c++multithreadingmutex

解决方案


在 Windows 上,std::mutex使用纤细的读取器/写入器锁实现。这种锁实现是不公平的(意味着它不保证等待线程获取锁的顺序)。一段时间前,Windows 放弃了公平锁,因为微软认为锁护卫队比线程饥饿更严重。

您可以在 Microsoft 文档上阅读有关超薄读取器/写入器锁的更多信息:Slim Reader/Writer (SRW) Locks

Joe Duffy 还在博客中讨论了公平与锁护卫问题:Windows Server 2003 SP1 和 Windows Vista 中的反护卫锁


推荐阅读