Информация об изменениях

Сообщение InterlockedExchange для enum от 09.09.2019 7:44

Изменено 09.09.2019 7:49 DDDX

InterlockedExchange для enum
Привет всем.

Хочу перейти на следующий уровень, но есть сомнения

Есть обычное перечисление — 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 можно сократить, но пока это не принципиально.
InterlockedExchange для enum
Привет всем.

Хочу перейти на следующий уровень, но есть сомнения

Есть обычное перечисление — 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.