inline operator T()
{
__sync_synchronize(); // Not sure this is overkill
return obj;
}
Короткая версия: это излишне.
Длинная версия:
Почему вы хотите реализовать этот класс как шаблон вообще? Это не имеет смысла, поскольку атомарные операции разрешены только для целочисленных типов от 1 до 8 байтов, и вы даже не можете быть уверены, что 8-байтовое целое число поддерживается на всех платформах.
Вы должны реализовать свой атомарный класс как не шаблонную версию и использовать «родной» целочисленный тип вашего оборудования / системы. Это int32_t на 32-битных процессорах / os и int64_t на 64-битных системах. e.g.:
#ifdef ...
typedef ... native_int_type;
#endif
// verify that you choosed the correct integer type
BOOST_STATIC_ASSERT(sizeof(native_int_type) == sizeof(void*));
BOOST_STATIC_ASSERT прямо в "static_assert ()" из C ++ 0x.
Если вы используете целочисленный тип «идеально подходит», вы можете написать оператор так:
operator native_int_type() { return obj; }
Поскольку obj является изменчивым, он гарантированно извлекает значение и не возвращает никакого кэшированного значения. А поскольку вы используете «родной» целочисленный тип, вы можете быть уверены, что чтение такого значения является атомарным.
atomic& operator=( native_integer_type val )
Опять же, вам не нужна синхронизация, если вы используете правильный целочисленный тип. Чтение / установка int32 в 32-битной системе Intel является атомарной, как и чтение / установка int64 в 64-битной системе.
Я не вижу никакой выгоды от использования атомарного в качестве шаблона. Атомные операции зависят от платформы. Лучше предложить класс «atomic_int», который просто гарантирует наличие как минимум 4 байта (если вы поддерживаете 32-битные и 64-битные системы) и «atomic_pointer», если вам это нужно. Таким образом, имя класса также подразумевает семантику и цель.
Если вы просто используете «атомарный», то можно подумать: «Ух, я просто должен поместить свой строковый класс в этот шаблон, и тогда он станет потокобезопасным!».
Редактировать: ответить на ваше обновление: «Я хочу убедиться, что операции согласованы, несмотря на переупорядочение чтения / записи из-за оптимизации компилятора».
Чтобы компилятор и процессор не переупорядочивали операции чтения / записи, вам нужна __sync_synchronize ().
Но учтите, что семантика получения / выпуска может дать лучшую производительность, чем полные барьеры.
Edit2:
inline atomic< T > & operator=( T val )
{
__sync_synchronize(); // Not sure if this is overkill
obj = val;
return *this;
}
Что вы хотите предотвратить переупорядочением? В большинстве случаев вы хотите написать это:
obj = val;
__sync_synchronize();
вместо этого. Поскольку вы хотите быть уверены, что значение записано, как только вы вернулись из функции.