Привет всем.
Хочу перейти на следующий уровень, но есть сомнения
Есть обычное перечисление — enum t_state{state__none,state__run,state__done};
Для переменной с типом t_state нужно замутить атомарный обмен значения.
std::atomic_exchange с enum работать не захотел, поэтому решил замутить велосипед.
Для атомарного обмена у меня есть штука вида:
class t_thread_traits__multi
{
public: //---------------------------------------------------------------
static int_type exchange(volatile LONG* const target,LONG const value)
{
return ::InterlockedExchange(target,value);
}
};//class t_thread_traits__multi
Если я все правильно понимаю, в основе enum лежит 4-байтный int, LONG тоже 4-байтный. Поэтому можно (осторожно) заюзать InterlockedExchange(LONG*,LONG) для enum t_state.
У меня получился такая (пробная) реализация t_thread_traits__multi::exchange, которая работает как с LONG так и с enum:
//assert_s - это аналог static_assert
class t_thread_traits__multi
{
public: //---------------------------------------------------------------
template<typename T1,typename T2>
static T1 exchange(volatile T1* const target,T2 const value);
private:
template<typename T1>
class tag_exchange__enum;
template<typename T1,typename T2>
class tag_exchange__std;
template<typename T1,typename T2,size_t sizeOfT1>
class tag_exchange__std2;
template<typename T1,typename T2>
class tag_exchange__std2<T1,T2,4>;
};//class t_thread_traits__multi
////////////////////////////////////////////////////////////////////////////////
//class t_thread_traits__multi
template<typename T1,typename T2>
inline T1 t_thread_traits__multi::exchange(volatile T1* const target,T2 const value)
{
typedef typename std::conditional<std::is_enum<T1>::value,tag_exchange__enum<T1>,tag_exchange__std<T1,T2> >::type
_e;
return _e::exec(target,value);
}//exchange
////////////////////////////////////////////////////////////////////////////////
//class t_thread_traits__multi::tag_exchange__enum
template<typename T1>
class t_thread_traits__multi::tag_exchange__enum
{
public:
static T1 exec(volatile T1* const target,T1 const value)
{
typedef typename std::underlying_type<T1>::type _ut;
assert_s(sizeof(_ut)==sizeof(T1));
return static_cast<T1>(tag_exchange__std<_ut,_ut>::exec((_ut*)target,static_cast<_ut>(value)));
}//exec
};//struct t_thread_traits__multi::tag_exchange__enum
////////////////////////////////////////////////////////////////////////////////
//class t_thread_traits__multi::tag_exchange__std
template<typename T1,typename T2>
class t_thread_traits__multi::tag_exchange__std
{
public:
static T1 exec(volatile T1* const target,T2 const value)
{
return tag_exchange__std2<T1,T2,sizeof(T1)>::exec(target,value);
}//exec
};//struct t_thread_traits__multi::tag_exchange__std
////////////////////////////////////////////////////////////////////////////////
//class t_thread_traits__multi::tag_exchange__std2
template<typename T1,typename T2>
class t_thread_traits__multi::tag_exchange__std2<T1,T2,4>
{
public:
static T1 exec(volatile T1* const target,T2 const value)
{
assert_s(sizeof(T1)==4);
assert_s(sizeof(LONG)==4);
return (T1)::InterlockedExchange((LONG*)target,value);
}//exec
};//struct t_thread_traits__multi::tag_exchange__std2
Это не сильно корявое решение?
Промежуточный tag_exchange__std можно сократить, но пока это не принципиально.
UPD. Решение должно работать начиная с Visual Studio 2013.
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Здравствуйте, Коваленко Дмитрий, Вы писали:
КД>Привет всем.
КД>Хочу перейти на следующий уровень, но есть сомнения
Посмотрел (здесь) как решение выглядит и осознал корявость, дырявость и перемудренность
Исправленный вариант:
////////////////////////////////////////////////////////////////////////////////
template<typename T1,typename T2>
inline T1 t_thread_traits__multi::exchange(volatile T1* const target,T2 const value)
{
typedef typename std::conditional
<std::is_enum<T1>::value,
tag_exchange__enum<T1>,
tag_exchange__std >::type
_e;
return _e::exec(target,value);
}//exchange
////////////////////////////////////////////////////////////////////////////////
//class t_thread_traits__multi::tag_exchange__enum
template<typename T1>
class t_thread_traits__multi::tag_exchange__enum
{
public:
static T1 exec(volatile T1* const target,T1 const value)
{
typedef typename std::underlying_type<T1>::type _ut;
assert_s(sizeof(_ut)==sizeof(T1));
return static_cast<T1>
(tag_exchange__std::exec
((_ut*)target,
static_cast<_ut>(value)));
}//exec
};//struct t_thread_traits__multi::tag_exchange__enum
////////////////////////////////////////////////////////////////////////////////
//class t_thread_traits__multi::tag_exchange__std
class t_thread_traits__multi::tag_exchange__std
{
public:
static LONG exec(volatile LONG* const target,LONG const value)
{
return ::InterlockedExchange(target,value);
}//exec
static int exec(volatile int* const target,int const value)
{
assert_s(sizeof(LONG)==sizeof(int));
return (int)::InterlockedExchange((LONG*)target,(LONG)value);
}//exec
};//struct t_thread_traits__multi::tag_exchange__std
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Здравствуйте, Коваленко Дмитрий, Вы писали:
КД>Привет всем.
КД>Хочу перейти на следующий уровень, но есть сомнения
КД>Есть обычное перечисление — enum t_state{state__none,state__run,state__done};
КД>Для переменной с типом t_state нужно замутить атомарный обмен значения.
КД>std::atomic_exchange с enum работать не захотел, поэтому решил замутить велосипед...
enum t_state{state__none,state__run,state__done};
std::atomic<t_state> value;
value.exchange(state__none);
Что и где не работает? Под Windows внутри вызывается именно InterlockedExchange.
Здравствуйте, Alexander G, Вы писали:
КД>>std::atomic_exchange с enum работать не захотел, поэтому решил замутить велосипед.
AG>Зачем самодельная на WinAPI, получить unterlying type, и использовать std::atomic на нём, будет чисто и портабельно.
Да это все последствия программирования под Z80 в далеком детстве.
exchange мне нужен строго в одном месте. в остальных можно просто присваивать.
А в std::atomic все присваивания через _InterlockedExchange идут
Боюсь будет тормозить
| На всякий случай |
| Это я шучу так
Спасибо, скорее всего заюзаю. Надо только на 2013-ой "что как" посмотреть. |
| |
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Здравствуйте, Коваленко Дмитрий, Вы писали:
КД>exchage мне нужен строго в одном месте. в остальных можно просто присваивать.
КД>А в std::atomic все присваивания через _InterlockedExchange идут
Почитал про std::atomic.
Похоже тут можно "рулить" типами синхронизации.
И memory_order_relaxed как раз указывает на то, что никакой синхронизации не требуется.
---
Правда тут нужно еще подумать — эта экономия на спичках вообще нужна? ...
-- Пользователи не приняли программу. Всех пришлось уничтожить. --