Модераторы: Daevaorn
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Очень быстрая синхронизация, ну прям очень очень быстрая 
:(
    Опции темы
cupper
Дата 17.5.2012, 17:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 525
Регистрация: 29.11.2006

Репутация: 1
Всего: 1



Делаем кроссплатформенно. В общем такая проблема. Есть два потока, T1, T2. T1 крутится в цикле, с интервалом в 5mcs (тобишь очень быстро). В Т2 цикл выполняется с интервалов в 300 миллисекунд.
Нужно между ними синхронизатор две переменный (одна структура из двух полей).
Код

struct State
{
enum Action{A, B,C};

Action act;
time_t last_update;
}


Т.е. действие выполненное в T1 и время когда оно было выполнено. Нужно сделать минимальную задержку в T1. Так что мютексы, отпадают.
Есть две идеи:
1. В структура State добавляем булев флаг (аля критической секции)
Код

struct State
{
enum Action{A, B,C};

bool lock;

Action act;
time_t last_update;
}

// В потоке T1
while(boost::atomic_cas32(state.lock, true, false)) {};

state.act = ...
state.last_update = time(NULL)

boost::atomic_write(state.lock, false);

// В потоке T2 аналогично
...

Плохо то, что если и Т1 и Т2 выполняются одним ядром (псевдо мультипоточность) и мы например в Т1 начали работу (state.lock = true), потом планировщик переключился в T2, то T2 будет болтаться в пустом цыкле, пока управление не будет передано опять в T1 который освободит псевдомютекс. Вообще вероятность этого велика ли ? что столь мелкие части кода будет вставлено переключение контекстов ? Самая долгая операция будет time(NULL).

2. Обе переменные State вместить в одну int64 и работать с ней атомарно. Это будет вообще без блокировок. Но просто лень возиться с побитовыми операциями smile Ну и плюс, ограничение 32-х битного time_t
PM MAIL   Вверх
Леопольд
Дата 17.5.2012, 22:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 943
Регистрация: 17.6.2009

Репутация: 10
Всего: 13



Может можно сделать проще с обычным мьютексом?

Код


void thr1()
{
   while(...)
   {
      // делаем что-то
      time_t t = time();
      if(last_update != t)
      {
         scoped_lock lock(mutex);
         // меняем обе переменные
      }
      else
      {
         // атомарно меняем одну переменную
      }
      
   }
}

void thr2()
{
   while(...)
   {
      {
          scoped_lock lock(mutex);
          // читаем значение переменных
      }
   }
}

смысл в том что синхронизация будет происходить не чаще чем раз в секунду (при условии что оба потока одновременно залочили мьютекс).

Это сообщение отредактировал(а) Леопольд - 18.5.2012, 08:04


--------------------
вопросов больше чем ответов
PM MAIL   Вверх
bsa
Дата 17.5.2012, 23:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 63
Всего: 196



Цитата(cupper @  17.5.2012,  18:42 Найти цитируемый пост)
 Обе переменные State вместить в одну int64 и работать с ней атомарно.

что-то я не уверен, что абсолютно все процессоры могут атомарно с такими переменными работать. Просто может получиться так, что эта атомарность будет реализована через мьютекс...
PM   Вверх
volatile
Дата 18.5.2012, 00:05 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 37
Всего: 85



Цитата(cupper @  17.5.2012,  17:42 Найти цитируемый пост)
enum Action{A, B,C};
Action act;

Если экшенов немного. 3, как здесь или 4, то можно попытаться их запихать с time_t в одну атомарную 32-битную переменную.
за счет младших битов например, или старших, смотря чем вы готовы пожертвовать, точностью или абсолютной величиной.

это и будет, имхо 
Цитата(cupper @  17.5.2012,  17:42 Найти цитируемый пост)
Очень быстрая синхронизация, ну прям очень очень быстрая 

 smile 


PM MAIL   Вверх
Леопольд
Дата 18.5.2012, 08:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 943
Регистрация: 17.6.2009

Репутация: 10
Всего: 13



Цитата(bsa @  17.5.2012,  23:35 Найти цитируемый пост)
что-то я не уверен, что абсолютно все процессоры могут атомарно с такими переменными работать. Просто может получиться так, что эта атомарность будет реализована через мьютекс... 

Да и time_t скоро будет 64 бита.
Хотя, тут можно "схитрить", из потока в поток передавать только N младших бит, недостающие биты брать из сискола time()

Но мне больше по душе первый вариант. IMHO, он производительнее (нет второго сискола) и правильно хендлится смена сис. времени.

Это сообщение отредактировал(а) Леопольд - 18.5.2012, 08:19


--------------------
вопросов больше чем ответов
PM MAIL   Вверх
cupper
Дата 18.5.2012, 14:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 525
Регистрация: 29.11.2006

Репутация: 1
Всего: 1



Цитата(Леопольд @  17.5.2012,  22:32 Найти цитируемый пост)
смысл в том что синхронизация будет происходить не чаще чем раз в секунд

думал об этом. Но это может привести к по секундному провалу времени выполнения th1.
Цитата(bsa @  17.5.2012,  23:35 Найти цитируемый пост)
что-то я не уверен, что абсолютно все процессоры могут атомарно с такими переменными работать. Просто может получиться так, что эта атомарность будет реализована через мьютекс... 

Вот это уже боле печалька. Но задача решается под конкретного заказчика, с не сказать что топовыми, но и не со старыми серверами. 

Цитата(volatile @  18.5.2012,  00:05 Найти цитируемый пост)
Если экшенов немного. 3, как здесь или 4, то можно попытаться их запихать с time_t в одну атомарную 32-битную переменную.

Порядок важен до  секунд до 10-20 (а может и 60-ти, зависит от настройки). 32битная time_t мне и так уже душу режит что это только до 2038 года smile
Состояний у меня не больше 8. Т.е. 3 млашие бита, т.е. точность до 8 секунд. Думаю пойдет. В крайнем случае можно расширить до 4 бит, и точность будет до 16 секунд, что тоже приемлемо. Но думаю, из за пункта выше, это в принципе не так важно. Но зато, наконец то до меня дошло как решить проблему 2038 года для себя smile


Цитата(Леопольд @  18.5.2012,  08:06 Найти цитируемый пост)
Да и time_t скоро будет 64 бита.

То, что разработка ведется на 64 битной системе, но собирается под x32 не дает мне понять сейчас time_t уже 64 для любой архитектуры или все еще зависит от разрядности ? Может можно как то явно обращаться к time64 ? Под винду это есть _time64, но вот под линукс... там я что то этого не нашел. 

Цитата(Леопольд @  18.5.2012,  08:06 Найти цитируемый пост)
Хотя, тут можно "схитрить", из потока в поток передавать только N младших бит, недостающие биты брать из сискола time()

не понял.
PM MAIL   Вверх
Леопольд
Дата 18.5.2012, 20:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 943
Регистрация: 17.6.2009

Репутация: 10
Всего: 13



Цитата(cupper @  18.5.2012,  14:08 Найти цитируемый пост)
не понял.


Код

std::atomic<uint32_t> data;

void thr1()
{
   ...
   std::uint32_t local_data = static_cast<std::uint32_t>(::time()) << 4;
   local_data |= local_flag; // local_flag шириной в 4 бита
   data.store(local_data, std::memory_order_release);
   ...
}

void thr2()
{
   ...
   std::uint32_t local_data = data.load(std::memory_order_acquire);
   if( (local_data >> 4) & 0xFFFFFFF != 0xFFFFFF) // условие добавил после коммента volatile
   {   
      local_flag = static_cast<EnumType>(local_data & 0xF);
      local_time = (::time() & ~0xFFFFFFF) | static_cast<time_t>(local_data >> 4) ;
   }
   ...
}


Цитата(cupper @  18.5.2012,  14:08 Найти цитируемый пост)
думал об этом. Но это может привести к по секундному провалу времени выполнения th1.
В смысле посекундному? Если это не риалтайм, то ничего страшного если один раз в секунду потоки будут синхронно получать доступ к переменным. Как только поток проапдейтил/прочитал переменную, мьютекс сразуже разлочивается, тут счёт на микросекунды. Преждевременная оптимизация - зло, впрочем IMHO, меньшее чем преждевременная пессимизация...

Ты не рассматривал возможность использования condition variable?

Это сообщение отредактировал(а) Леопольд - 19.5.2012, 10:40


--------------------
вопросов больше чем ответов
PM MAIL   Вверх
volatile
Дата 18.5.2012, 23:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 37
Всего: 85



Цитата(Леопольд @  18.5.2012,  20:50 Найти цитируемый пост)
   time_t local_time = (::time() & ~0xFFF) | static_cast<time_t>(local_data >> 4) ;

Леопольд, не очень хороший код.  smile 
Между вывовами время, может измениться. и где гарантия что это не затронет 4 старших бита?
маловероятно, пожалуй. Но тем не менее, не чисто.
(Раз неприятность может случиться, то по законам Мерфи она обязательно случится).

Цитата(cupper @  18.5.2012,  14:08 Найти цитируемый пост)
Порядок важен до  секунд до 10-20 (а может и 60-ти, зависит от настройки)

Ну раз так, что проще запихать экшены, просто в младщие разряды.
Можно конечно и сохранить точность времени, как предложил Леопольд, путем дополнительного вызова ::time(),
но там толко нужно делать округление.
Но раз это не столь необходимо, то это, уже видимо оверкилл.
задача же стояла, "самое быстрое..."

 

Это сообщение отредактировал(а) volatile - 19.5.2012, 01:04
PM MAIL   Вверх
Леопольд
Дата 19.5.2012, 10:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 943
Регистрация: 17.6.2009

Репутация: 10
Всего: 13



Цитата(volatile @  18.5.2012,  23:50 Найти цитируемый пост)
Между вывовами время, может измениться. и где гарантия что это не затронет 4 старших бита?
маловероятно, пожалуй. Но тем не менее, не чисто.

Это будет происходить раз в 8 лет, думаю можно как-то похендлить это "переполнение" , например не доверять значениям (local_data >> 4) & 0xFFFFFFF == 0xFFFFFFF.
Цитата(Леопольд @  18.5.2012,  08:06 Найти цитируемый пост)
Но мне больше по душе первый вариант. IMHO, он производительнее (нет второго сискола) и правильно хендлится смена сис. времени.


Добавлено @ 10:28
Цитата(volatile @  18.5.2012,  23:50 Найти цитируемый пост)
Леопольд, не очень хороший код.
Константа неправильная, должна быть 0xFFFFFFF (поправил в примере)


Это сообщение отредактировал(а) Леопольд - 19.5.2012, 10:40


--------------------
вопросов больше чем ответов
PM MAIL   Вверх
cupper
Дата 21.5.2012, 08:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 525
Регистрация: 29.11.2006

Репутация: 1
Всего: 1



Цитата(Леопольд @  18.5.2012,  20:50 Найти цитируемый пост)
Если это не риалтайм, то ничего страшного если один раз в секунду потоки будут синхронно получать доступ к переменным. Как только поток проапдейтил/прочитал переменную, мьютекс сразуже разлочивается, тут счёт на микросекунды. Преждевременная оптимизация - зло


Не реалтайм, но счет идет как раз на микросекунды. Даже лишнее переключение потоков уже наверно скажется на общей картине.
Цитата(Леопольд @  18.5.2012,  20:50 Найти цитируемый пост)
Ты не рассматривал возможность использования condition variable?

не тот случай.
Цитата(volatile @  18.5.2012,  23:50 Найти цитируемый пост)
Между вывовами время, может измениться. и где гарантия что это не затронет 4 старших бита?
маловероятно, пожалуй. Но тем не менее, не чисто.
(Раз неприятность может случиться, то по законам Мерфи она обязательно случится).

Я не понял подход, как это должно работать с 4 младшими битами и дополнительным time ?

Опустим переменную состояние. Оставим только время time32_t

в потоке th1 оно должно обновляться на каждой итерации цикла (или например с интервалом в 1-20 секунду) (это имело бы смысл если бы операции > И = сильно различались по времени в пользу >. Но они же по сути с одинаковой скоростью выполняются, так смысл усложнять ?)
Код

while true
do_something()
if(CurTime - lastTime > 10 sec)
     a.time = CurTime

в потоке th2 каждый 300 миллисекунд считывается a.time. 

Куда втыкается 
Код

  time_t local_time = (::time() & ~0xFFF) | static_cast<time_t>(local_data >> 4) ;

и зачем ?
PM MAIL   Вверх
volatile
Дата 21.5.2012, 23:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 37
Всего: 85



Цитата(cupper @  21.5.2012,  08:39 Найти цитируемый пост)
Куда втыкается 
  time_t local_time = (::time() & ~0xFFF) | static_cast<time_t>(local_data >> 4) ;
и зачем ? 


Это вопрос ко мне?

PM MAIL   Вверх
cupper
Дата 22.5.2012, 16:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 525
Регистрация: 29.11.2006

Репутация: 1
Всего: 1



Цитата(volatile @ 21.5.2012,  23:20)
Цитата(cupper @  21.5.2012,  08:39 Найти цитируемый пост)
Куда втыкается 
  time_t local_time = (::time() & ~0xFFF) | static_cast<time_t>(local_data >> 4) ;
и зачем ? 


Это вопрос ко мне?

вадимо нет, резко поменялась задача, ту пришлось пока отложить. Но курс на реализацию уже выбран. 
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0698 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.