Як може std :: lock_guard бути швидшим, ніж std :: mutex :: lock ()?


9

Я сперечався з колегою, про lock_guard, і він запропонував, щоб lock_guard був повільніше повільний, ніж mutex :: lock () / mutex :: unlock () через вартість екземпляра та unistantiate класу lock_guard.

Тоді я створив цей простий тест і, несподівано, версія з lock_guard майже в два рази швидша за версію з mutex :: lock () / mutex :: 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 разів за кожен пробіг. Зазвичай більш пізні вимірювання будуть такими, які насправді мають значення, тому що кеш-пам'ять до тих пір перетвориться на будь-яку поведінку, яка, ймовірно, матиме в довгостроковій перспективі.
Познач Федра

2
Навіть якщо це std::lock_guardбуло трохи повільніше, якщо ви не зможете довести, що це має значення з точки зору продуктивності, збільшення швидкості не призведе до недійсності інших переваг використання std::lock_guard(в основному RAII). Якщо що- g++небудь може кинути або що-небудь, що може перетворитися на щось потенційно складніше в майбутньому, вам майже доведеться використовувати якийсь об’єкт, щоб володіти замком.
Франсуа

Відповіді:


6

Збірка випуску дає однаковий результат для обох версій.

У DEBUGзбірки показує ~ 33% більше часу для func2; різницю я бачу в розборці, яка func2використовує __security_cookieта викликає @_RTC_CheckStackVars@8.

Ви терміни DEBUG?

EDIT: Крім того, переглядаючи 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  
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.