Russian Qt Forum
Май 04, 2024, 23:23 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало Форум WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  
  Просмотр сообщений
Страниц: 1 ... 111 112 [113] 114 115 ... 140
1681  Qt / Многопоточное программирование, процессы / Re: AtomicData или механизм атомарной операции записl : Апрель 01, 2011, 12:03


Мне кажется тема зашла в тупик, на мой взгляд гораздо лучше/полезнее было бы обсудить вот это
В смысле, можно создать внутренний буфер (массив тобиш). Пока читатели читают из одной ячейки массива, писатель, чтоб не простаивать пишет в следующую, и после того как запишет устанавливает индекс для чтения с актуальными данными. При этом в следующий раз писатель будет выбирать новый индекс для записи с учётом того, откуда читают данные читатели. Короче, читатели всегда будут знать где актуальные даные, а писатели будут знать куда писать, чтобы не было простоев.
Конечно в новой теме

Давайте создадим, как предлагаете назвать? И ещё для этого, если использовать только абстрактные rwlocker нужно мне бы хотелось знать логику их работы. 
1682  Qt / Многопоточное программирование, процессы / Re: AtomicData или механизм атомарной операции записи данных : Апрель 01, 2011, 12:00
Цитировать
Про Ваш мьютекс. Там опять присвоение, и оно опять компрометирует атомарность:

T1, T2 пришли, захватили ключи 0 и 1, key = 1
T1 отработал и ушёл, key = -1
T2 решил сделать --key, и завис навсегда (между key = -1 и -2)
Нет, не зависнет он навсегда, поскольку key-- будет только тогда, когда tmp > 0

Цитировать
lock_read ()
   {
      while (true)
      {
          scoped_lock sl (m_mutex);
          if (!m_writer)
          {
             ++m_readers;
             return;
          }
      }
   }
А что такое scoped_lock ? И как он устроен?
1683  Qt / Многопоточное программирование, процессы / Re: AtomicData или механизм атомарной операции записи данных : Март 31, 2011, 14:17
Цитировать
понятно, что имея настоящий мьютекс можно реализовать всё, что угодно. На этом этапе математики зачехляют линейки, а программисты идут писать тесты. Правда код я не проверял, сегодня только придумал вечером, так что критику интересно бы услышать  Крутой
Хорошо, предположим, что у нас есть такой мьютекс (реализованный без CAS) И как с помощью него сделать lock-free?
Вот пример самого мьютекса:
Код
C++ (Qt)
class mutex
{
  atomic_int key = -1;
public:
  lock ()
  {
      int tmp = 0;
      do {
         tmp = ++key;
         if (tmp) key--;
     } while (tmp != 0);
  }
 
  unlock ()
  {
     key = -1;
  }
};
 
1684  Qt / Многопоточное программирование, процессы / Re: AtomicData или механизм атомарной операции записи данных : Март 31, 2011, 11:03
Нужно увеличивать скважность импульса, например, отказаться от остатка кванта
Шокированный кажется я понимаю! ..да нет, кого я обманываю.. Смеющийся

Но интересный вариант Вы описали, правда смущает ограничение на одного пишущего и завис писателя, если поток читателей постоянный. Но в реализации подкопаться не к чему (кроме опечатки Подмигивающий. А работает это потому, что каждая атомарная переменная используется только в атомарных операциях, а m_ax всё время компрометировал атомарность присвоением. Если отказаться от присвоений, то задача становится проще, потому что огород городить сложнее.

1) Ну "только один писатель" вполне usable, а вот без pending (запрос на запись) прожить трудно.

Кстати, зачем write_pending, почему нельзя просто ставить write (как у Akon, только CAS вместо fetchAndXor)? Ну то есть чтобы читатели не подвесили писателя, как я понял понял, но вроде бы одного write достаточно и короче получится, нет?


Собственно с CAS это другой класс задач уже, тут можно уже делать wait-free, не то что спинлоки (кстати, CAS сам по себе такое же wait-free, как и атомарный ++).

Теперь по сути задачи, которую решал m_ax: как сделать рв-спинлок без CAS? Как известно в математике и некоторых дугих религиях, задача станет ещё проще, если отказаться от задачи. А именно, реализовать обычный, а не рв-лок, например так:

Код
C++ (Qt)
struct mutex
{
  atomic_int n = 0;
  int level = 1;
 
  lock ()
  {
      int nn = ++n; //atomic pre increment
      while (nn != level);
  }
 
  unlock ()
  {
     level = nn + 1; //non-atomic, but protected by our newborn mutex!
  }
};
 

понятно, что имея настоящий мьютекс можно реализовать всё, что угодно. На этом этапе математики зачехляют линейки, а программисты идут писать тесты. Правда код я не проверял, сегодня только придумал вечером, так что критику интересно бы услышать  Крутой
А в функции unlock,  nn - это что? Если это тот atomic_int n, то тогда такая ситуация:
Первый поток вызывает lock (n = 1, level = 1), но до unlock ещё не успевает дойти. В этот момент другой поток вызывает lock (n = 2, level = 1). Соответственно он не проходит и крутится в цикле. Затем, первый поток вызывает unlock (level = 2+1 = 3), что не освобождает второй поток, который продолжает крутится в цикле.    
Лучше изменить unlock так:
Код
C++ (Qt)
void unlock ()
{
   level++;
}
 
1685  Qt / Многопоточное программирование, процессы / Re: AtomicData или механизм атомарной операции записи данных : Март 30, 2011, 13:11
m_ax, просьба: давайте по пустому не месить и форум понапрасну не утомлять.

Догнать а что же такое STATE_READ_AND_WRITE - мудрено. Что-то типа "Rat but blue"?  Улыбающийся

Код
C++ (Qt)
   static bool acquireRead(AtomicInt &counter, AtomicInt &state) {
 
       int tmp = (state |= STATE_READ);
       if (tmp == STATE_READ) {
 
Как уже не раз говорилось, между этими 2-мя строчками может произойти многое, "просто if" здесь не катит (поезд уже ушел)

Я уважаю желание "докопаться самому" и с подозрением отношусь к "начитавшимся классов", но чего ж об один камень 10 раз спотыкаться?  Улыбающийся  Зачем упорно избегать CAS который предназначен для решения таких коллизий? Зачем рыть себе яму привлекая вторую переменную за которой надо (мучительно) следить?

Да, Вы правы. Пора завязывать с этой темой)
Всем спасибо за обсуждение)
1686  Qt / Многопоточное программирование, процессы / Re: AtomicData или механизм атомарной операции записи данных : Март 29, 2011, 19:12
R0 читает; state == STATE_READ
R1 читает; state == STATE_READ и дочитывает; state == STATE_FREE
W0 начинает писать (в то время как R0 все еще читает)

Согласен  Грустный

Исправил этот момент, введя счётчик читающих потоков: m_counter. Теперь state = STATE_FREE только когда все читатели перестанут читать:
Код
C++ (Qt)
#ifndef SPINLOCK_H
#define SPINLOCK_H
 
#include <assert.h>
#include <cstdatomic>
 
template <class T>
class SpinLock
{
public:
   typedef atomic<int> AtomicInt;
   SpinLock()  : m_key(-1), m_state(STATE_FREE), m_counter(0) {}
 
   void setData(const T &data) {
       while (!acquireWrite(m_key, m_state));
       m_data = data;
       releaseWrite(m_key, m_state);
   }
   T getData() const {
       while (!acquireRead(m_counter, m_state));
       T data = m_data;
       releaseRead(m_counter, m_state);
       return data;
   }
private:
   enum { STATE_FREE = 0, STATE_READ = 1, STATE_WRITE = 2, STATE_READ_AND_WRITE = 3 };
   AtomicInt m_key;
   AtomicInt m_state;
   AtomicInt m_counter;
   T m_data;
   //-------------------------------------------------------------------------
 
   static bool acquireWrite(AtomicInt &key, AtomicInt &state) {
 
       int tmp = (state |= STATE_WRITE);
       if (tmp == STATE_READ_AND_WRITE) {
           state = STATE_READ;
           return false;
       }
       bool tmp2 = (++key == 0);
       key = 0;
       return tmp2;
   }
   //-------------------------------------------------------------------------
 
   static void releaseWrite(AtomicInt &key, AtomicInt &state) {
       state = STATE_FREE;
       key = -1;
   }
   //-------------------------------------------------------------------------
 
   static bool acquireRead(AtomicInt &counter, AtomicInt &state) {
 
       int tmp = (state |= STATE_READ);
       if (tmp == STATE_READ) {
           counter++;
           return true;
       }
       state = STATE_WRITE;
       return false;
 
   }
   //-------------------------------------------------------------------------
 
   static void releaseRead(AtomicInt &counter, AtomicInt &state) {
       if (--counter == 0)
           state = STATE_FREE;
   }
   //-------------------------------------------------------------------------
};
 
 
#endif // SPINLOCK_H
 
Вот так)
1687  Qt / Многопоточное программирование, процессы / Re: AtomicData или механизм атомарной операции записи данных : Март 29, 2011, 18:07
Никак не даёт покоя идея реализации этого злосчастного SpinLock.
Несколько пересмотрел логику и теперь это выглядит так:
Код
C++ (Qt)
#ifndef SPINLOCK_H
#define SPINLOCK_H
 
#include <assert.h>
#include <cstdatomic>
 
template <class T>
class SpinLock
{
public:
   typedef atomic<int> AtomicInt;
   SpinLock()  : m_key(-1), m_state(STATE_FREE) {}
 
   void setData(const T &data) {
       while (!acquireWrite(m_key, m_state));
       m_data = data;
       releaseWrite(m_key, m_state);
   }
   T getData() const {
       while (!acquireRead(m_key, m_state));
       T data = m_data;
       releaseRead(m_key, m_state);
       return data;
   }
private:
   enum { STATE_FREE = 0, STATE_READ = 1, STATE_WRITE = 2, STATE_READ_AND_WRITE = 3 };
   AtomicInt m_key;
   AtomicInt m_state;
   T m_data;
   //-------------------------------------------------------------------------
 
   static bool acquireWrite(AtomicInt &key, AtomicInt &state) {
 
       int tmp = (state |= STATE_WRITE);
       if (tmp == STATE_READ_AND_WRITE) {
           state = STATE_READ;
           return false;
       }
       bool tmp2 = (++key == 0);
       key = 0;
       return tmp2;
   }
   //-------------------------------------------------------------------------
 
   static void releaseWrite(AtomicInt &key, AtomicInt &state) {
       state = STATE_FREE;
       key = -1;
   }
   //-------------------------------------------------------------------------
 
   static bool acquireRead(AtomicInt &/*key*/, AtomicInt &state) {
 
       int tmp = (state |= STATE_READ);
       if (tmp == STATE_READ)
           return true;
       state = STATE_WRITE;
       return false;
 
   }
   //-------------------------------------------------------------------------
 
   static void releaseRead(AtomicInt &/*key*/, AtomicInt &state) {
      state = STATE_FREE;
   }
   //-------------------------------------------------------------------------
};
 
 
#endif // SPINLOCK_H
 


Краткое описание:
Есть две переменные key и state.
state может принимать следующие значения:
00 = 0 - STATE_FREE;
01 = 1 - STATE_READ;
10 = 2 - STATE_WRITE;
11 = 3 - STATE_READ_AND_WRITE; (виртуальное состояние)

key нужин лишь для того, чтобы отобрать какой либо один поток для записи.  

Как Вам такой вариант?  Улыбающийся
1688  Qt / Многопоточное программирование, процессы / Re: AtomicData или механизм атомарной операции записи данных : Март 29, 2011, 12:22
Это интересно обсудить, но выделите пожалуйста в отдельную тему (предполагаем что какой-то ReadWriteLock имеется)

Отдаленно похожая, но тоже интересная, идея обсуждалась тут (http://alenacpp.blogspot.com/2010/07/blog-post_30.html).
Интересно) Спасибо, меня тут как раз одна идея осинила)

Цитировать
Это интересно обсудить, но выделите пожалуйста в отдельную тему (предполагаем что какой-то ReadWriteLock имеется)
Хорошо, как освобожусь так напишу в отдельную тему)
1689  Qt / Многопоточное программирование, процессы / Re: AtomicData или механизм атомарной операции записl : Март 29, 2011, 11:10
Если удасца реализовать первоночальный SpinLock, то его можно будет ускорить создав буфер даных. Тогда простои при записи и чтении можно будет существенно сократить. 
Не понял, расскажите подробнее
В смысле, можно создать внутренний буфер (массив тобиш). Пока читатели читают из одной ячейки массива, писатель, чтоб не простаивать пишет в следующую, и после того как запишет устанавливает индекс для чтения с актуальными данными. При этом в следующий раз писатель будет выбирать новый индекс для записи с учётом того, откуда читают данные читатели. Короче, читатели всегда будут знать где актуальные даные, а писатели будут знать куда писать, чтобы не было простоев.
Мне проще код накидать)) Но это когда разберусь со SpinLock ом. 
1690  Qt / Многопоточное программирование, процессы / Re: AtomicData или механизм атомарной операции записи данных : Март 29, 2011, 10:58
Цитировать
R читает
W пришёл и сделал bool tmp = (++state_write == 0);
R вышел и установил state_write = -1
W установил state_write = 0 и завис навсегда
а мы вот так:
Код
C++ (Qt)
static bool acquireWrite(AtomicInt &readers, AtomicInt &state_write) {
 
       bool tmp = (++state_write == 0);
       if (tmp && !readers)
           return true;
 
       state_write = 0;
       return false;
   }
 
Улыбающийся
1691  Qt / Многопоточное программирование, процессы / Re: AtomicData или механизм атомарной операции записи данных : Март 29, 2011, 10:20
Хм.. Ещё один вариант, надеюсь последний)
Код
C++ (Qt)
#ifndef SPINLOCK_H
#define SPINLOCK_H
 
#include <assert.h>
#include <cstdatomic>
 
template <class T>
class SpinLock
{
public:
   typedef atomic<int> AtomicInt;
   SpinLock()  : m_count_readers(0), m_state_write(-1) {}
 
   void setData(const T &data) {
       while (!acquireWrite(m_count_readers, m_state_write));
       m_data = data;
       releaseWrite(m_state_write);
   }
   T getData() const {
       while (!acquireRead(m_count_readers, m_state_write));
       T data = m_data;
       releaseRead(m_count_readers, m_state_write);
       return data;
   }
private:
   AtomicInt m_count_readers;
   AtomicInt m_state_write;
   T m_data;
 
   static bool acquireWrite(AtomicInt &readers, AtomicInt &state_write) {
 
       bool tmp = (++state_write == 0);
       state_write = 0;
 
       return (tmp && !readers);
   }
   //-------------------------------------------------------------------------
 
   static void releaseWrite(AtomicInt &state_write) {
       state_write = -1;
   }
   //-------------------------------------------------------------------------
 
   static bool acquireRead(AtomicInt &readers, AtomicInt &state_write) {
 
       readers++;
       bool tmp = (++state_write == 0);
       state_write = 0;
 
       if (tmp) {
           state_write = -1;
           return true;
       }
       readers--;
       return false;
   }
   //-------------------------------------------------------------------------
 
   static void releaseRead(AtomicInt &readers, AtomicInt &state_write) {
       if(--readers == 0)
           state_write = -1;
   }
   //-------------------------------------------------------------------------
};
 
 
#endif // SPINLOCK_H
 
Во всяком случае, ситуация описанная brankovic:
Цитировать
R0 читал
R1 дошёл до if, увидел, что кто-то читает, отправился на else
R1 заснул
R0 ушёл (readers == 0)
W пришёл и захватил на запись
R1 проснулся, сделал ++readers и вернул true

теперь R0 читает, а W пишет
исключена.
1692  Qt / Многопоточное программирование, процессы / Re: AtomicData или механизм атомарной операции записи данных : Март 28, 2011, 20:23
Короче, окончательный вариант SpinLock:
Код
C++ (Qt)
#ifndef SPINLOCK_H
#define SPINLOCK_H
 
#include <assert.h>
#include <cstdatomic>
 
template <class T>
class SpinLock
{
public:
   typedef atomic<int> AtomicInt;
   SpinLock()  : m_count_readers(0), m_state_write(-1) {}
 
   void setData(const T &data) {
       while (!acquireWrite(m_count_readers, m_state_write));
       m_data = data;
       releaseWrite(m_state_write);
   }
   T getData() const {
       while (!acquireRead(m_count_readers, m_state_write));
       T data = m_data;
       releaseRead(m_count_readers, m_state_write);
       return data;
   }
private:
   AtomicInt m_count_readers;
   AtomicInt m_state_write;
   T m_data;
 
   static bool acquireWrite(AtomicInt &readers, AtomicInt &state_write) {
 
       bool tmp = (++state_write == 0);
       state_write = 0;
 
       return (tmp && !readers);
   }
   //-------------------------------------------------------------------------
 
   static void releaseWrite(AtomicInt &state_write) {
       state_write = -1;
   }
   //-------------------------------------------------------------------------
 
   static bool acquireRead(AtomicInt &readers, AtomicInt &state_write) {
 
       if (!readers) {
           int tmp = (++state_write == 0);
           readers = tmp;
       }
       else
           readers++;
 
       return readers;
   }
   //-------------------------------------------------------------------------
 
   static void releaseRead(AtomicInt &readers, AtomicInt &state_write) {
       if (--readers == 0)
           state_write = -1;
   }
   //-------------------------------------------------------------------------
};
 
#endif // SPINLOCK_H
 
1693  Qt / Многопоточное программирование, процессы / Re: AtomicData или механизм атомарной операции записl : Март 28, 2011, 20:09
это как-то уж слишком коварно.. По смыслу m_ax спинлок хотел, а в спинлоке так и должно быть.
Не должно. Про свой OSX могу сказать: OSSpinLockLock (спиннер) не просто "крутит while". А TBB сначала просто делает какое-то число nop, затем вставляет pause а потом уж shed_yield. При этом учитывается специфика процессора. В общем, это на порядок сложнее чем то что сейчас обсуждается  Улыбающийся  

А без этого (увы) могут быть заметные тормоза для др. задач
Если удасца реализовать первоночальный SpinLock, то его можно будет ускорить создав буфер даных. Тогда простои при записи и чтении можно будет существенно сократить. 
1694  Qt / Многопоточное программирование, процессы / Re: AtomicData или механизм атомарной операции записи данных : Март 28, 2011, 19:57
А что Вы скажите на это  Подмигивающий:
Код
C++ (Qt)
static bool acquireRead(AtomicInt &readers, AtomicInt &state_write) {
 
       if (!readers) {
           int tmp = (++state_write == 0);
           readers = tmp;
       }
       else
           readers++;
 
       return readers;
   }
 
1695  Qt / Многопоточное программирование, процессы / Re: AtomicData или механизм атомарной операции записи данных : Март 28, 2011, 19:12
Код
C++ (Qt)
       if (!readers)
           readers = (state_write == -1);
 
Те же грабли. Последняя строка не атомарна.
Цитировать
С Ларисой я действительно пил вино, но это было на пасху
Т.е. state_write действительно был -1, но до тех пор пока это присвоится readers, др. нитка успеет захватить по записи.

Лучше держать все в одном AtomicInt. с двумя переменными заморочек намного больше. Ваше упорство избежать CAS "заслуживает лучшего применения"  Улыбающийся И как там у Вас с холостым ходом?
[/quote]
Не атомарно? Ну это можно исправить следующим образом:
Код
C++ (Qt)
static bool acquireRead(AtomicInt &readers, AtomicInt &state_write) {
 
       if (!readers)
           readers = 1; // атомарно
           int tmp = (state_write == -1); // атомарно
           readers = tmp; // атомарно
       else
           readers++;
 
       return readers;
   }
 
Цитировать
И как там у Вас с холостым ходом?
В смысле? С ним что-то не так?
Страниц: 1 ... 111 112 [113] 114 115 ... 140

Страница сгенерирована за 0.294 секунд. Запросов: 24.