Подтвердить что ты не робот

Почему std:: atomic <bool> намного медленнее, чем volatile bool?

Я использую volatile bool в течение многих лет для управления исполнением потоков, и он отлично работал

// in my class declaration
volatile bool stop_;

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

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

Теперь, поскольку С++ 11 добавила поддержку для атомных операций, я решил попробовать вместо этого

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

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

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

Но он на несколько порядков медленнее, чем volatile bool!

Простой тестовый сценарий, который я написал, занимает около 1 секунды для завершения подхода volatile bool. С std::atomic<bool> однако я ждал около 10 минут и сдался!

Я попытался использовать флаг memory_order_relaxed с load и store с тем же эффектом.

Моя платформа: Windows 7 64 бит MinGW gcc 4.6.x

Что я делаю неправильно?

UPD

Да, я знаю, что volatile не делает переменную нить безопасной. Мой вопрос не о неустойчивом, о том, почему атомный смехотворно медленный.

UPD2 @all, спасибо за ваши комментарии - я попробую все предлагаемые, когда я доберусь до своей машины сегодня вечером.

4b9b3361

Ответ 1

Код от "Olaf Dietsche"

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

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

ЕСЛИ ВЫ ИСПОЛЬЗУЕТЕ СКОРОСТЬ GCC 4.7

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

Добавлена ​​поддержка атомных операций с указанием модели памяти С++ 11/C11. Эти новые __атомные подпрограммы заменяют существующие встроенные процедуры __sync.

Атомная поддержка также доступна для блоков памяти. Команды блокировки будут использоваться, если блок памяти имеет одинаковый размер и выравнивание в качестве поддерживаемого целочисленного типа. Атомные операции, которые не имеют блокировки, остаются в виде вызовов функций. Набор библиотечных функций доступен на атомной вики GCC в разделе "Библиотека внешней атомной информации".

Так что да.. только решение - перейти на GCC 4.7

Ответ 2

Поскольку мне это интересно, я сам тестировал его на Ubuntu 12.04, AMD 2.3 ГГц, 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;
}

Скомпилирован с g++ -g -std=c++0x -O3 a.cpp

Хотя, тот же вывод, что и @aleguna:

  • just bool:

    real 0m0.004s
    пользователь 0m0.000s
    sys 0m0.004s

  • volatile bool:

    $time./a.out
    real 0m1.413s
    пользователь 0m1.368s
    sys 0m0.008s

  • std::atomic<bool>:

    $time./a.out
    реальный 0m32.550s
    пользователь 0m32.466s
    sys 0m0.008s

  • std::atomic<int>:

    $time./a.out
    real 0m32.091s
    пользователь 0m31.958s
    sys 0m0.012s

Ответ 3

Я предполагаю, что это аппаратный вопрос. Когда вы пишете volatile, вы говорите компилятору, чтобы он ничего не принимал в отношении переменной, но, как я понимаю, аппаратное обеспечение по-прежнему будет рассматривать ее как обычную переменную. Это означает, что переменная будет в кэше все время. Когда вы используете атом, вы используете специальные аппаратные инструкции, которые, вероятно, означают, что переменная извлекается из основной памяти каждый раз, когда она используется. Разница во времени согласуется с этим объяснением.