foo 循环内外的互斥锁速度差异

use*_*204 5 multithreading thread-synchronization c++11

我对在 for 循环内外使用互斥锁 () 和解锁 () 之间的速度不同感到困惑。我得到了一个全局变量值和一个将它增加 1000000 次的函数。此函数由 5 个线程并行运行。我测量了经过的时间并得到了这些结果:

    mutex.lock();
    for(int i = 0; i < 1000000; i++)
    {
        value++;
    }
    mutex.unlock();
Run Code Online (Sandbox Code Playgroud)

0.160921 秒

和:

    for(int i = 0; i < 1000000; i++)
    {        
        mutex.lock();
        value++;
        mutex.unlock();
    }
Run Code Online (Sandbox Code Playgroud)

2.10521 秒

我假设使用第二个内部互斥体排列控制太精细并且在线程切换之间花费了大量时间?或者还有别的东西吗?

Seb*_*edl 4

锁定和解锁互斥体需要一些时间。具体来说,它比递增整数需要更多的时间。您的第二个示例只是测试锁定/解锁速度,并且还增加了任务切换开销,因为在互斥体解锁的任何点上,不同的线程都可以接管。

在第一种情况下,编译器只需通过一次加法来替换循环。而且由于线程的整个功能都被互斥体覆盖,因此不存在并行执行;除了一个线程之外的所有线程都会被阻塞,直到该线程的循环完成为止,这意味着该代码相当于在单个线程上连续循环五次。

这与细粒度锁定和粗粒度锁定关系不大。这些策略与您是否有很少的锁覆盖大量资源,还是有很多锁覆盖很少的资源有关。您只有一种资源(全局 int),因此无需做出决定。

相反,这是关于是否仅在短时间内锁定互斥体,从而使其在其余时间保持开放状态以供其他线程执行工作,或者锁定较长时间以避免开销,但会降低并行性。但是,由于您的线程除了访问受保护的资源之外不执行任何操作,因此不存在“其余时间”。您的问题(将整数递增 5000000 次)首先没有固有的并行性,因此多个线程无法利用。