C++ 为什么 std::atomic<bool> 比 volatile bool 慢得多?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13135834/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 17:00:57  来源:igfitidea点击:

Why is std::atomic<bool> much slower than volatile bool?

c++multithreadingperformancec++11atomic

提问by

I've been using volatile bool for years for thread execution control and it worked fine

多年来,我一直在使用 volatile bool 进行线程执行控制,并且运行良好

// in my class declaration
volatile bool stop_;

-----------------

// In the thread function
while (!stop_)
{
     do_things();
}

Now, since c++11 added support for atomic operations, I decided to try that instead

现在,由于 c++11 添加了对原子操作的支持,我决定尝试一下

// in my class declaration
std::atomic<bool> stop_;

-----------------

// In the thread function
while (!stop_)
{
     do_things();
}

But it's several orders of magnitude slower than the volatile bool!

但它比volatile bool!慢了几个数量级。

Simple test case I've written takes about 1 second to complete with volatile boolapproach. With std::atomic<bool>however I've been waiting for about 10 minutes and gave up!

我编写的简单测试用例需要大约 1 秒钟才能完成volatile bool。随着std::atomic<bool>不过,我一直在等待约10分钟,并放弃了!

I tried to use memory_order_relaxedflag with loadand storeto the same effect.

我尝试使用memory_order_relaxedflagloadstore达到相同的效果。

My platform: Windows 7 64 bit MinGW gcc 4.6.x

我的平台:Windows 7 64 位 MinGW gcc 4.6.x

What I'm doing wrong?

我做错了什么?

UPD

UPD

Yes, I know that volatile does not make a variable thread safe. My question is not about volatile, it's about why atomic is ridiculously slow.

是的,我知道 volatile 不会使可变线程安全。我的问题不是关于 volatile,而是关于为什么 atomic 慢得离谱。

UPD2@all, thank you for your comments - I will try all the suggested when I get to my machine tonight.

UPD2@all,感谢您的评论-今晚我到达我的机器时,我会尝试所有建议的内容。

采纳答案by KoKuToru

Code from "Olaf Dietsche"

来自“Olaf Dietsche”的代码

 USE ATOMIC
 real   0m1.958s
 user   0m1.957s
 sys    0m0.000s

 USE VOLATILE
 real   0m1.966s
 user   0m1.953s
 sys    0m0.010s

IF YOU ARE USING GCC SMALLER 4.7

如果您使用的是 GCC 更小 4.7

http://gcc.gnu.org/gcc-4.7/changes.html

http://gcc.gnu.org/gcc-4.7/changes.html

Support for atomic operations specifying the C++11/C11 memory model has been added. These new __atomic routines replace the existing __sync built-in routines.

Atomic support is also available for memory blocks. Lock-free instructions will be used if a memory block is the same size and alignment as a supported integer type. Atomic operations which do not have lock-free support are left as function calls. A set of library functions is available on the GCC atomic wiki in the "External Atomics Library" section.

添加了对指定 C++11/C11 内存模型的原子操作的支持。这些新的 __atomic 例程替换了现有的 __sync 内置例程。

原子支持也可用于内存块。如果内存块的大小和对齐方式与支持的整数类型相同,则将使用无锁指令。没有无锁支持的原子操作保留为函数调用。GCC atomic wiki 的“外部原子库”部分提供了一组库函数。

So yeah .. only solution is to upgrade to GCC 4.7

所以是的..唯一的解决方案是升级到 GCC 4.7

回答by Olaf Dietsche

Since I'm curious about this, I tested it myself on Ubuntu 12.04, AMD 2.3 GHz, gcc 4.6.3.

因为我对此很好奇,所以我自己在 Ubuntu 12.04、AMD 2.3 GHz、gcc 4.6.3 上进行了测试。

#if 1
#include <atomic>
std::atomic<bool> stop_(false);
#else
volatile bool stop_ = false;
#endif

int main(int argc, char **argv)
{
    long n = 1000000000;
    while (!stop_) {
        if (--n < 0)
            stop_ = true;
    }

    return 0;
}

Compiled with g++ -g -std=c++0x -O3 a.cpp

编译为 g++ -g -std=c++0x -O3 a.cpp

Although, same conclusion as @aleguna:

虽然,与@aleguna 的结论相同:

  • just bool:

    real 0m0.004s
    user 0m0.000s
    sys 0m0.004s

  • volatile bool:

    $ time ./a.out
    real 0m1.413s
    user 0m1.368s
    sys 0m0.008s

  • std::atomic<bool>:

    $ time ./a.out
    real 0m32.550s
    user 0m32.466s
    sys 0m0.008s

  • std::atomic<int>:

    $ time ./a.out
    real 0m32.091s
    user 0m31.958s
    sys 0m0.012s

  • 只是bool

    真实 0m0.004s
    用户 0m0.000s
    系统 0m0.004s

  • volatile bool

    $ time ./a.out
    real 0m1.413s
    user 0m1.368s
    sys 0m0.008s

  • std::atomic<bool>

    $ time ./a.out
    real 0m32.550s
    user 0m32.466s
    sys 0m0.008s

  • std::atomic<int>

    $ time ./a.out
    real 0m32.091s
    用户 0m31.958s
    系统 0m0.012s

回答by Olle Lindeberg

My guess is that this is an hardware question. When you write volatile you tell the compiler to not assume anything about the variable but as I understand it the hardware will still treat it as a normal variable. This means that the variable will be in the cache the whole time. When you use atomic you use special hardware instructions that probably means that the variable is fetch from the main memory each time it is used. The difference in timing is consistent with this explanation.

我的猜测是这是一个硬件问题。当您编写 volatile 时,您会告诉编译器不要对变量进行任何假设,但据我了解,硬件仍会将其视为普通变量。这意味着该变量将一直在缓存中。当您使用 atomic 时,您会使用特殊的硬件指令,这可能意味着每次使用该变量时都会从主内存中获取该变量。时间上的差异与这个解释是一致的。