Re: InterlockedExchange для enum
От: Videoman Россия https://hts.tv/
Дата: 09.09.19 15:33
Оценка: 8 (1)
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>Привет всем.


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


КД>Есть обычное перечисление — 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.
Re: InterlockedExchange для enum
От: Alexander G Украина  
Дата: 10.09.19 09:30
Оценка: 8 (1)
Здравствуйте, Коваленко Дмитрий, Вы писали:


КД>std::atomic_exchange с enum работать не захотел, поэтому решил замутить велосипед.


Зачем самодельная на WinAPI, получить unterlying type, и использовать std::atomic на нём, будет чисто и портабельно.
Русский военный корабль идёт ко дну!
InterlockedExchange для enum
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 09.09.19 07:44
Оценка:
Привет всем.

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

Есть обычное перечисление — 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.
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Отредактировано 09.09.2019 7:49 DDDX . Предыдущая версия .
Re: InterlockedExchange для enum
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 09.09.19 08:09
Оценка:
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>Привет всем.


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


Посмотрел (здесь) как решение выглядит и осознал корявость, дырявость и перемудренность

Исправленный вариант:

////////////////////////////////////////////////////////////////////////////////

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
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[2]: InterlockedExchange для enum
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 10.09.19 09:56
Оценка:
Здравствуйте, Alexander G, Вы писали:

КД>>std::atomic_exchange с enum работать не захотел, поэтому решил замутить велосипед.


AG>Зачем самодельная на WinAPI, получить unterlying type, и использовать std::atomic на нём, будет чисто и портабельно.


Да это все последствия программирования под Z80 в далеком детстве.

exchange мне нужен строго в одном месте. в остальных можно просто присваивать.
А в std::atomic все присваивания через _InterlockedExchange идут

Боюсь будет тормозить

  На всякий случай
Это я шучу так

Спасибо, скорее всего заюзаю. Надо только на 2013-ой "что как" посмотреть.
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[3]: InterlockedExchange для enum
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 10.09.19 11:22
Оценка:
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>exchage мне нужен строго в одном месте. в остальных можно просто присваивать.

КД>А в std::atomic все присваивания через _InterlockedExchange идут

Почитал про std::atomic.

Похоже тут можно "рулить" типами синхронизации.

И memory_order_relaxed как раз указывает на то, что никакой синхронизации не требуется.

---
Правда тут нужно еще подумать — эта экономия на спичках вообще нужна? ...
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.