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

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

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Ограничить ReadWriteLock  (Прочитано 11011 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« : Май 05, 2012, 11:54 »

Добрый день

Есть список, каждый элемент имеет собственный ReadWriteLock. Все работает, но иногда наступает заметное замедление. Профайлер показывает что тормозит захват элемента по чтению - ну получается так что всем ниткам нужно какое-то небольшое число элементов, к которым все они щемятся по чтению - вот и получается интенсивная конкуренция на локе. Заранее неизвестно какие это элементы и будет ли такая ситуация вообще. Также в процессе работы те или иные элементы могут оказаться "часто востребованными". Напр на первой минуте это элемент 2, потом уже элемент 10 и.т.п. Расходы "по записи" малы, иногда запись не происходит никогда - просто с ней надо считаться.

Как это порешать ?   

Спасибо
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #1 : Май 05, 2012, 13:33 »

Версия кутехи какая?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #2 : Май 05, 2012, 13:46 »

Версия кутехи какая?
Никакая, используется tbb::spin_rw_mutex но даже он притормаживает. Вообще как реализован ReadWriteLock здесь без разницы
Записан
V1KT0P
Гость
« Ответ #3 : Май 05, 2012, 13:58 »

Как это порешать ?   
Если чтение не меняет данные, то сделай чтоб мьютекс блокировался только на момент записи. Тогда тормоза будут когда все нитки начнут чтение в момент записи. А если есть возможность реализовать запись из одной нитки, размер данных позволяет без проблем делать копию и по условию задачи можно на время записи отдавать старые данные, то можно вообще без мьютексов обойтись. Чтение производить без мьютексов, данные засунуть в умный указатель. При записи делать копию и менять умный указатель. Если кто-то читал старые данные то после завершения старые данные самоуничтожатся, а последующие уже будут вытягивать новые данные.
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #4 : Май 05, 2012, 14:42 »

Igors
Вообще-то имеет, но, я так подозреваю спинлок реализован через атомики и быстрее его не сделать.

Нужно больше информации о задаче - как так получается, что много тредов так сильно конкурируют за один элемент списка. Получается, что время работы треда сравнимо с ожиданием на локе что ли? В таком случае, возможно надо менять алгоритм - делать меньше тредов так, чтобы тред выполнял несколько задач над одним эл-том.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #5 : Май 05, 2012, 15:02 »

Избегаю цитирования чтобы покороче

Задача банальна: работа с большими картинками (или большим их числом) которые все в память не влазят. Поэтому они разбиты на фрагменты (tiles). Если затребованный пиксель находится в выгруженном фрагменте - он подгружается. При этом возможно др фрагмент вытесняется на диск (простой LRU).

Если работаем с такими "виртуальными" имеджами, то никуда не денешься - для обращения к каждому пикселю нужно брать лок. Конечно атомарный. И это работает - за исключением ситуаций описанных выше.

Задумка сделать часть фрагментов (по существу "страниц") резидентными , ну или "невыгружаемыми". Но этим надо как-то управлять (пока не пойму как Улыбающийся)
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #6 : Май 05, 2012, 16:45 »

Я не про атомарность лока, а про то, реализован он через атомик инты (test&set) или нет. Ну да не суть.

Можно ли в треде кешировать элемент, к которому обращались в последний раз?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #7 : Май 05, 2012, 18:04 »

Я не про атомарность лока, а про то, реализован он через атомик инты (test&set) или нет. Ну да не суть.
Да, через CAS

Можно ли в треде кешировать элемент, к которому обращались в последний раз?
Можно, захватив его по чтению мы можем скопировать. Но нитка делает множество обращений к разным имеджам и/или разным частям одного имеджа. Поэтому сначала надо как-то собрать статистику, а где ее хранить и как обновлять?  Также перезапись 64к в местный буфер выглядит глуповато учитывая что один элемент может интенсивно использоваться всеми нитками. Также 1 элемент в локальном кэше - мало, а больше - растут расходы на проверку. Ведь время обращения к пикселю мало
Записан
alexis031182
Гость
« Ответ #8 : Май 06, 2012, 11:42 »

Возможно ли перевести поток на работу с другим фрагментом изображения (или может быть пикселем), если превышен заранее определённый лимит обращений к этому фрагменту? То есть ввести счётчик заблокированных потоков у каждого пикселя. Если обращения потоков идут к рядом стоящим пикселям, то, возможно, счётчики блокировок можно было бы вести для групп пикселей. Это по идее снизит накладные расходы. Как-то так...
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #9 : Май 06, 2012, 14:30 »

Возможно ли перевести поток на работу с другим фрагментом изображения (или может быть пикселем), если превышен заранее определённый лимит обращений к этому фрагменту? То есть ввести счётчик заблокированных потоков у каждого пикселя. Если обращения потоков идут к рядом стоящим пикселям, то, возможно, счётчики блокировок можно было бы вести для групп пикселей. Это по идее снизит накладные расходы. Как-то так...
Что-то не очень ясно "как" Улыбающийся Практически любое приложение обращается к ф-циям типа GetPixel на самом низком уровне. С точки зрения вызывающего делать какие-то движения в зависимости от куда попало GetPixel нереально - это может быть только вшито в саму GetPixel и быть "opaque" для вызывающего.

Ладно, допустим (пока) как-то резидентные элементы назначены. Тогда смотрится совсем неплохо. Псевдокод
Код
C++ (Qt)
if (!element->mResidentFlag)   // если элемент нерезидентный (выгружаемый)
element->AcquireRead();      // захватываем по чтению
 
AtomicInc(element->mNumAccess);    // увеличиваем число обращений к элементу
AtomicInc(theTotalAccess);   // увеличиваем общее обращений ко всем элементам
 
Теперь надо как-то лихо ставить/убирать mResidentFlag в зависимости от счетчиков
Записан
alexis031182
Гость
« Ответ #10 : Май 06, 2012, 15:56 »

Что-то не очень ясно "как" Улыбающийся Практически любое приложение обращается к ф-циям типа GetPixel на самом низком уровне. С точки зрения вызывающего делать какие-то движения в зависимости от куда попало GetPixel нереально - это может быть только вшито в саму GetPixel и быть "opaque" для вызывающего.
То есть на уровне вызывающего потока координаты пиксела не известны?

Ладно, допустим (пока) как-то резидентные элементы назначены. Тогда смотрится совсем неплохо. Псевдокод
...
Теперь надо как-то лихо ставить/убирать mResidentFlag в зависимости от счетчиков
Объясните, пожалуйста, а для чего задумана "резидентность" элементов? Для чего часть элементов делать невыгружаемыми?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #11 : Май 06, 2012, 16:16 »

То есть на уровне вызывающего потока координаты пиксела не известны?
Конечно известны, но использовать их для чего-либо (кроме получения цвета/значения пикселя) мягко говоря "неудобно"

Объясните, пожалуйста, а для чего задумана "резидентность" элементов? Для чего часть элементов делать невыгружаемыми?
Чтобы избежать потерь на локе (см первый пост темы)
Записан
alexis031182
Гость
« Ответ #12 : Май 06, 2012, 16:26 »

Понял... значит задача, получается, сводится к тому, как снять флаг "частой востребованности" с элемента, верно? Если установить его с помощью счётчика обращений не проблема, то убрать...

А в конце работы с данными пиксела не создаётся никакого события, чтобы его можно было прикрутить к декрементации счётчика обращений?
« Последнее редактирование: Май 06, 2012, 16:28 от alexis031182 » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #13 : Май 06, 2012, 16:35 »

Понял... значит задача, получается, сводится к тому, как снять флаг "частой востребованности" с элемента, верно? Если установить его с помощью счётчика обращений не проблема, то убрать...
Верно, но пока я не знаю даже как установить

А в конце работы с данными пиксела не создаётся никакого события, чтобы его можно было прикрутить к декрементации счётчика обращений?
После того как пиксель использован его надо освободить (был захвачен по чтению). Счетчик обращений накапливает общее число обращений (а не текущее использование)
Записан
alexis031182
Гость
« Ответ #14 : Май 06, 2012, 16:48 »

Понял... значит задача, получается, сводится к тому, как снять флаг "частой востребованности" с элемента, верно? Если установить его с помощью счётчика обращений не проблема, то убрать...
Верно, но пока я не знаю даже как установить
Почему нельзя хотя бы для начала просто привязаться к какой-нибудь константе? Например
Код:
if(element->mNumAccess > 99) element->setResidentFlag(true);

После того как пиксель использован его надо освободить (был захвачен по чтению). Счетчик обращений накапливает общее число обращений (а не текущее использование)
Желательно наверное всё-таки использование. Для чего инкрементацию счётчика нужно поместить до
Код:
element->AcquireRead();
Иначе от счётчика мало толку, получается
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


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