2个线程比1慢?

Moh*_*oun 7 c++ performance multithreading c++11 stdthread

我正在玩耍,std::thread出现了一些奇怪的东西:

#include <thread>

int k = 0;

int main() {
    std::thread t1([]() { while (k < 1000000000) { k = k + 1; }});
    std::thread t2([]() { while (k < 1000000000) { k = k + 1; }});

    t1.join();
    t2.join();

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

在使用clang ++编译上面的代码而没有优化时,我得到了以下基准:

real 0m2.377s  
user 0m4.688s  
sys  0m0.005s
Run Code Online (Sandbox Code Playgroud)

然后我将代码更改为以下内容:(现在只使用1个线程)

#include <thread>

int k = 0;

int main() {
    std::thread t1([]() { while (k < 1000000000) { k = k + 1; }});

    t1.join();

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这些是新的基准:

real 0m2.304s
user 0m2.298s
sys  0m0.003s
Run Code Online (Sandbox Code Playgroud)

为什么使用2个线程的代码比使用1的代码慢?

Mat*_*son 15

你有两个线程争夺同一个变量,k.因此,你花时间在处理器上说"处理器1:嘿,你知道它有什么价值k吗?处理器2:当然,你走了!",每隔几次更新来回拨打乒乓球.由于k不是原子的,所以也不能保证thread2不会写出"旧"值,k以便下次线程1读取该值时,它会跳回1,2,10 或100步,并且必须执行此操作再次 - 从理论上讲,这可能导致每个循环都没有完成,但这需要相当多的坏运气.

  • @Magtheridon96:除了Mats所说的,你的程序有一个数据竞争,因此正式未定义的行为._Anything_可能会发生,因为您从两个线程访问共享的非原子变量而没有同步.x86处理器的内存模型有点宽松,但你真的不应该依赖它. (7认同)
  • @Magtheridon96:简单地使`k`和`​​std :: atomic <int>`会阻止数据竞争,但它不会使乒乓问题消失,因为表达式"k = k + 1"仍然不是原子的.但是,`k ++`或`k + = 1`会.但是原子操作强制执行的处理器之间的同步,即使是无锁,仍然会导致开销 - 这根本不是可以使用线程加速的用例.把它想象成试图和你的朋友一起写故事 - 它不会比单独做更快,因为你必须轮流. (7认同)
  • @Magtheridon96:`std :: atomic`无法帮助这两个线程之间共享数据的事实 - 事实上,它使得它在原子FORCES处理器上的每次写入都会变得更糟糕在"原子"部分内部"放弃"其值的副本并等待"原子"完成,然后才能获取新值.这就是为什么在线程之间共享大量数据通常是SLOWER而不是在单个线程中运行. (2认同)