Bagaimana std :: lock_guard lebih cepat dari std :: mutex :: lock ()?


9

Saya berdebat dengan seorang kolega, tentang lock_guard, dan dia mengusulkan bahwa lock_guard mungkin lebih lambat daripada mutex :: lock () / mutex :: unlock () karena biaya instantiate dan unistantiate class lock_guard.

Lalu saya membuat tes sederhana ini dan, anehnya, versi dengan lock_guard hampir dua kali lebih cepat daripada versi dengan 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;
}

Hasil di mesin saya:

Take: 41 ms
Take: 22 ms

Adakah yang bisa menjelaskan mengapa dan bagaimana hal ini bisa terjadi?


2
dan berapa kali Anda melakukan pengukuran?
— artm

7
Silakan kirim flag kompiler Anda ... Pembandingan akan tergantung pada tingkat optimisasi ...
— Macmade

10
Kiat Pro: Saat melakukan pengukuran seperti ini, tukar pesanan untuk memastikan itu bukan hanya data / instruksi dingin yang menyebabkan masalah: coliru.stacked-crooked.com/a/81f75a1ab52cb1cc
— NathanOliver

2
Hal lain yang membantu ketika melakukan pengukuran seperti ini: letakkan semuanya dalam satu lingkaran yang lebih besar, sehingga Anda menjalankan set pengukuran keseluruhan, katakanlah, 20 kali setiap kali berjalan. Biasanya pengukuran nanti akan menjadi yang benar-benar bermakna, karena pada saat itu cache telah menetap ke perilaku apa pun yang mungkin terjadi dalam jangka panjang.
— Mark Phaedrus

2
Meskipun std::lock_guardsedikit lebih lambat, kecuali Anda dapat membuktikan bahwa itu penting dalam hal kinerja, kenaikan kecepatan tidak akan membatalkan manfaat lain dari penggunaan std::lock_guard(terutama RAII). Jika g++ada sesuatu yang bisa melempar atau apapun yang mungkin berubah menjadi sesuatu yang berpotensi lebih rumit di masa depan Anda hampir harus menggunakan semacam objek untuk memiliki kunci.
— François Andrieux

Jawaban:


6

Rilis build menghasilkan hasil yang sama untuk kedua versi.

The DEBUGbuild menunjukkan ~ 33% lebih lama waktu untuk func2; perbedaan yang saya lihat di pembongkaran yang func2menggunakan __security_cookiedan memanggil @_RTC_CheckStackVars@8.

Apakah Anda menghitung waktu DEBUG?

EDIT: Selain itu, ketika melihat RELEASEpembongkaran, saya perhatikan bahwa mutexmetode disimpan dalam dua pendaftar:

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

dan dipanggil dengan cara yang sama dari keduanya func1dan func2:

010F1067  call        edi  
....
010F107F  call        ebx  
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.