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

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 [2]   Вниз
  Печать  
Автор Тема: проверка объекта на существование по указателю  (Прочитано 20922 раз)
fuCtor
Гость
« Ответ #15 : Июнь 24, 2012, 13:16 »

А зачем нужен это класс если чтение/запись указателей и так атомарны?
Обычно чем больше классов человек знает - тем хуже он отвечает на такие вопросы. Ну посмотрим, может в этот раз будет "приятное исключение"  Улыбающийся

Чтение/запись да, но ИМХО основная цель атомарных классов (как их правильней назвать хз) сделать атомарной операцию сравнение с присваиванием, чтение с присваиванием и т.п. В обычном случае, это несколько отдельных команд, в процессе выполнения которых может быть гонка.

Код:
QAtomicPointer<T> p;
T* pT = p.fetchAndStoreRelaxed(NULL);
delete pT;
Я правильно понял?

Я бы еще добавил проверку инициализации указателя в виде:
Код:
QAtomicPointer<T> p; //общий указатель на что-то, который инициализирует один из потоков, а остальные используют
// следовательно нужна проверить был ли указатель уже создан
if(!p)
{
  T * pt = new T;
  if( !p.testAndSetRelaxed(0, pt) )
  {
    delete pt;
  }
}

Таким образом если указатель пуст, то ему будет присвоено значение, тогда другие проходя эту точку уже увидят, что значение не нулевое и удалят временный объект. Как-то так. А удаление да, как указано у вас можно реализовать, тоже будет исключена гонка между чтением - записью.

UPD: поправил сообщение в контексте вопроса  Строит глазки
« Последнее редактирование: Июнь 24, 2012, 13:45 от fuCtor » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #16 : Июнь 24, 2012, 16:54 »

Таким образом если указатель пуст, то ему будет присвоено значение, тогда другие проходя эту точку уже увидят, что значение не нулевое и удалят временный объект. Как-то так.
Так-то оно так, но действие странное: создали новый указатель, пытаемся его подсунуть, не получилось - удаляем созданный. Затрудняюсь придумать когда это нужно. Во всяком случае гораздо чаще нужно заменить предыдущий указатель на новый, а старый удалить.
Код
C++ (Qt)
void ReplacePtr( T *& oldP, T * newP )
{
// ???
}
 
Serr500 уже предложил 2 рабочих варианта, однако в первом дорогой мутекс, а во втором нам придется везде тащить/объявлять QAtomicPointer, что конечно пережить можно, но хотелось бы иметь нормальный указатель, а в нужный момент (и используя нужные классы внутри ReplacePtr) его заместить. Как это сделать?
Записан
fuCtor
Гость
« Ответ #17 : Июнь 24, 2012, 17:16 »

Таким образом если указатель пуст, то ему будет присвоено значение, тогда другие проходя эту точку уже увидят, что значение не нулевое и удалят временный объект. Как-то так.
Так-то оно так, но действие странное: создали новый указатель, пытаемся его подсунуть, не получилось - удаляем созданный. Затрудняюсь придумать когда это нужно. Во всяком случае гораздо чаще нужно заменить предыдущий указатель на новый, а старый удалить.
Код
C++ (Qt)
void ReplacePtr( T *& oldP, T * newP )
{
// ???
}
 
Serr500 уже предложил 2 рабочих варианта, однако в первом дорогой мутекс, а во втором нам придется везде тащить/объявлять QAtomicPointer, что конечно пережить можно, но хотелось бы иметь нормальный указатель, а в нужный момент (и используя нужные классы внутри ReplacePtr) его заместить. Как это сделать?


Как вариант использовать активное ожидание и локальный статичный QAtomicInt как Spinlock:
Код
C++ (Qt)
void ReplacePtr( T *& oldP, T * newP )
{
  static QAtomicInt spinlock = 0;
  while(!spinlock.testAndSetRelaxed(0, 1));
  // тут делаем нужные операции, например
  if(oldP)
    delete oldP;
  oldP = newP;
  spinlock = 0; //Обязательно после всего и обязательно должен выполниться, иначе deadlock
}
 
Т.к. предполагается что тело функции маленькое, то можно сделать и так, ну подождет пару тактов в цикле, все быстрей чем мьютексы ворочить.
« Последнее редактирование: Июнь 24, 2012, 17:19 от fuCtor » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #18 : Июнь 24, 2012, 17:34 »

Т.к. предполагается что тело функции маленькое, то можно сделать и так, ну подождет пару тактов в цикле, все быстрей чем мьютексы ворочить.
Так намного круче (атомарный лок куда быстрее). И лучше писать testAndSetAcquire - яснее чего хотим. Все же нельзя ли чище, без доп атомарной переменной?
Записан
fuCtor
Гость
« Ответ #19 : Июнь 24, 2012, 17:54 »

Т.к. предполагается что тело функции маленькое, то можно сделать и так, ну подождет пару тактов в цикле, все быстрей чем мьютексы ворочить.
Так намного круче (атомарный лок куда быстрее). И лучше писать testAndSetAcquire - яснее чего хотим. Все же нельзя ли чище, без доп атомарной переменной?

Код
ASM
mov eax, spinlock_address
mov ebx, SPINLOCK_BUSY
wait_cycle:
lock xchg [eax], ebx
cmp ebx, SPINLOCK_FREE
jnz wait_cycle
 
;<body>
 
mov eax, spinlock_address
mov ebx, SPINLOCK_FREE
lock xchg [eax], ebx
 
Взято с http://ru.wikipedia.org/wiki/Spinlock  Смеющийся

А так без атомарных ИМХО никак, другие (их тех что знаю) не дают 100% гарантии в отсутствии гонки.
Записан
shirushizo
Гость
« Ответ #20 : Июнь 25, 2012, 10:52 »

Горячие финские парни, про потоки я упомянул вскользь и уже об этом жалею Улыбающийся
Слишком далеко ушли от вопроса темы Подмигивающий
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #21 : Июнь 25, 2012, 11:27 »

Горячие финские парни, про потоки я упомянул вскользь и уже об этом жалею Улыбающийся
Слишком далеко ушли от вопроса темы Подмигивающий
Жалеть надо автора темы, который играется с чужими классами не понимая языка  Улыбающийся
В С/C++ нет средств проверки валидности адреса, известно лишь что 0-адрес невалиден. Никогда не понимал почему такие вопросы привлекают и получают немало ответов

Взято с http://ru.wikipedia.org/wiki/Spinlock  Смеющийся

А так без атомарных ИМХО никак, другие (их тех что знаю) не дают 100% гарантии в отсутствии гонки.
Все-таки лучше так
Код
C++ (Qt)
void ReplacePtr( T *& oldP, T * newP )
{
  static QAtomicInt spinlock = 0;
  while(!spinlock.testAndSetAcquire(0, 1)) {}
  T * doomed = oldP;
  oldP = newP;
  spinlock = 0;
  delete doomed;
}
Т.к. вызов delete (с эвентуальным деструктором) - совсем не пара тактов
А можно и без статика
Код
C++ (Qt)
template <class T>
void ReplacePtr( T *& oldP, T * newP )
{
T * doomed;
typedef QAtomicPointer <T> TAtom;
TAtom * ta = (TAtom *) &oldP;
for (;;) {
doomed = oldP;
if (ta->testAndSetAcquire(doomed, newP)) break;
}
delete doomed;
}
 
Несмотря на обилие Qt классов - не вижу как записать без приведения.
« Последнее редактирование: Июнь 25, 2012, 11:34 от Igors » Записан
Страниц: 1 [2]   Вверх
  Печать  
 
Перейти в:  


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