Почему 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, спасибо за ваши комментарии - я попробую все предлагаемые, когда я доберусь до своей машины сегодня вечером.
Ответы
Ответ 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, вы говорите компилятору, чтобы он ничего не принимал в отношении переменной, но, как я понимаю, аппаратное обеспечение по-прежнему будет рассматривать ее как обычную переменную. Это означает, что переменная будет в кэше все время.
Когда вы используете атом, вы используете специальные аппаратные инструкции, которые, вероятно, означают, что переменная извлекается из основной памяти каждый раз, когда она используется.
Разница во времени согласуется с этим объяснением.