std :: lock_guard如何比std :: mutex :: lock()更快?


9

我正在与一位同事讨论关于lock_guard的问题,他提出lock_guard可能比Mutex :: lock()/ Mutex :: unlock()慢一些,原因是实例化和取消了类lock_guard的成本。

然后,我创建了一个简单的测试,令人惊讶的是,使用lock_guard的版本几乎比使用互斥锁:: lock()/互斥锁:: unlock()的版本快两倍。

#include <iostream>
#include <mutex>
#include <chrono>

std::mutex m;
int g = 0;

void func1()
{
    m.lock();
    g++;
    m.unlock();
}

void func2()
{
    std::lock_guard<std::mutex> lock(m);
    g++;
}

int main()
{
    auto t = std::chrono::system_clock::now();
    for (int i = 0; i < 1000000; i++)
    {
        func1();
    }

    std::cout << "Take: " << std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - t).count() << " ms" << std::endl;

    t = std::chrono::system_clock::now();
    for (int i = 0; i < 1000000; i++)
    {
        func2();
    }

    std::cout << "Take: " << std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - t).count() << " ms" << std::endl;

    return 0;
}

我的机器上的结果:

Take: 41 ms
Take: 22 ms

有人可以弄清楚为什么以及怎么可能吗?


2
您进行了多少次测量?
artm

7
请发布您的编译器标志...基准测试将取决于优化级别...
Macmade

10
专家提示:在进行此类测量时,请交换订单以确保不仅仅是导致问题的冷数据/指令:coliru.stacked-crooked.com/a/81f75a1ab52cb1cc
NathanOliver

2
在进行这样的测量时,另一件有用的东西:将整个事情放在一个更大的循环中,这样就可以运行整个测量集,例如每次运行20次。通常,以后的测量将是实际上有意义的测量,因为到那时,高速缓存已经解决了长期可能发生的任何行为。
Mark Phaedrus,

2
即使std::lock_guard速度稍慢,除非您可以证明它对性能至关重要,否则速度的提高不会使使用std::lock_guard(主要是RAII)的其他好处无效。如果g++将来可能抛出的东西或可能会变得更复杂的东西,您几乎必须使用某种对象来拥有锁。
弗朗索瓦·安德列

Answers:


6

发行版本对两个版本产生相同的结果。

DEBUG构建示出了用于延长〜33%的时间func2; 我在func2使用__security_cookie和调用的反汇编中看到的差异@_RTC_CheckStackVars@8

您是否在安排调试时间?

编辑:此外,在查看RELEASE反汇编时,我注意到mutex方法保存在两个注册表中:

010F104E  mov         edi,dword ptr [__imp___Mtx_lock (010F3060h)]  
010F1054  xor         esi,esi  
010F1056  mov         ebx,dword ptr [__imp___Mtx_unlock (010F3054h)]  

并从func1和中以相同的方式调用func2

010F1067  call        edi  
....
010F107F  call        ebx  
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.