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

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

Страниц: 1 [2] 3   Вниз
  Печать  
Автор Тема: Частое добавление и удаление строки в QAbstractTableModel  (Прочитано 21027 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #15 : Февраль 12, 2016, 10:03 »

Мне кажется, что проблема в следующем. При вызове функции beginInsertRows испускается сигнал rowsAboutToBeInserted(), по нему объект QTableView выполняет в потоке вставку строк в себя. При endInsertRows испускается rowsInserted. Аналогично при вызове beginRemoveRows выделяется сигнал rowsAboutToBeRemoved и в потоке QTableView удаляет из View строку. Как синхронизировать эти потоки - для меня главный вопрос.
Не исключено что и "никак". Напр где-то "в недрах" есть код типа
Код
C++ (Qt)
// main thread
int numRow = model->rowCount();
for (int i = 0; i < numRow; ++i) {
// do something with row[i]
}
 
Если рабочая нитка в это время меняет число строк - вылет неизбежен. Нужно залочить код выше, но это может оказаться слишком трудным или вообще недостижимым. И никто не гарантирует что такой код не появится в след версии Qt.

С др стороны если сигналы с датчиков приходят интенсивно - какой смысл дергать UI на каждый чих? Логичнее накапливать/буферировать изменения а потом их скопом применить.

Мьютексы я пробовал делать, но не помогало. Если кто конкретно скажет, куда их поставить
На paint вьюхи точно нужен. Но я бы с этим вообще не связывался - это ненадежно
Записан
Bepec
Гость
« Ответ #16 : Февраль 12, 2016, 10:12 »

to Igors:
Почитайте про Model/View.
1) Все операции с контейнером который имеется лишь в наследнике, производятся ТОЛЬКО в наследнике.
2) Все операции производимые моделью берут данные из переопределённых методов, т.е. ColumnCount/RowsCount/Data.
3) Что модель не обрабатывает данные, а лишь отдаёт данные по сигналу View.
4) Никто не гарантирует что всё не изменится, если изменится в любом случае придётся переписывать, и ваши "предположения" ни к чему не приведут.
5) UI не дёргается на каждый чих. Дёргается только модель, а View обновляться будет с нормальной частотой и по необходимости. Это опять таки написано в пунктике Model/View.

Цитировать
На paint вьюхи точно нужен
- феерический бред. Модель работает с данными. Все методы работы с контейнером переопределены правильно, и как следствие нужно ставить мутекс только на них.

PS мне вот лично интересно как paint View может повлиять на данные в модели? Показает язык
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #17 : Февраль 12, 2016, 11:41 »

PS мне вот лично интересно как paint View может повлиять на данные в модели? Показает язык
Еще как повлияет, правда наоборот Улыбающийся Мне даже не хочется Вас пинать, все равно без толку, ничему не научитесь
Записан
YvenTitan
Самовар
**
Offline Offline

Сообщений: 174


Просмотр профиля
« Ответ #18 : Февраль 12, 2016, 14:40 »

Спасибо, Igors. Ваш код помог. Правда как только я вместо QAbstractTableModel стал использовать QSortFilterModel, то проблема вернулась, несмотря на то, что я перед функцией filterAcceptRow ставлю CScopedLock lock(m_Lock).
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #19 : Февраль 12, 2016, 15:05 »

Спасибо, Igors. Ваш код помог. Правда как только я вместо QAbstractTableModel стал использовать QSortFilterModel, то проблема вернулась, несмотря на то, что я перед функцией filterAcceptRow ставлю CScopedLock lock(m_Lock).
Простой пример тоже должен вылететь, пусть и через длительное время. Дело в том что лочить надо обоих (читающего и пишущего). Пример:
Код
C++ (Qt)
void MyDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const
{
<- пробой
...
}
Пусть пока рабочая нитка не обновляла модель. Все хорошо, пришел нормальный QModelIndex. И тут в точке "пробой" UI нитка заснула, а рабочая наоборот проснулась и грохнула строки. Затем главная просыпается, лезет model->data() по индексу, но он-то уже невалиден. Без разницы MyDelegate или стандартный Qt

Поэтому придется лочить paint целиком, sizeHint и вообще всех методы работающие с моделью в цикле. Сигналы с параметрами QModelIndex тоже станут невалидны. И даже если удастся обеспечить все локи - попадаем в др беду. Напр если удаление интенсивно - залоченному paint трудно прорваться, UI будет подвисать.

Поэтому думается что работа с моделью в др нитке - принципиально неверное решение
Записан
Bepec
Гость
« Ответ #20 : Февраль 12, 2016, 22:17 »

А теперь добавляем радость, что там когда грохнули данные стоит мутекс и он блокирует такую ситуацию Веселый Igors вы пытаетесь доказать, что используя защищённые мутексами функции для работы с данными можно порушить стек?

Просто надо пользоваться функциями модели, защищёнными мутексами и будет всё хорошо. Мутексы гораздо быстрее обновления ui. Хотя конечно зависит от нагрузки.

PS ну если конечно написать model->m_rowList[1], то будет вылет.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #21 : Февраль 13, 2016, 07:53 »

А теперь добавляем радость, что там когда грохнули данные стоит мутекс и он блокирует такую ситуацию Веселый
Для блокировки нужно чтобы мутекс был захвачен UI ниткой еще до вызова MyDelеgate::paint. А так рабочая нитка его захватывает, удаляет строки и освобождает, оставляя UI в интересном положении.
Записан
Bepec
Гость
« Ответ #22 : Февраль 13, 2016, 17:11 »

Блокировка происходит в модели. Пока там мутекс не освобождён стоит всё. И paint вызывает data, который ставит Mutex и который отдаёт данные. В один момент времени могут быть отданы данные, или же изменены данные. А т.к. данные нетяжелые и скорость изменения данных очень высока, то пользователь не заметит даже разницы работы модели с мутексом или без.

Model и View связаны сигналами, которые сами разруливают проблемы с Queued connection. Хотя тут тоже вопрос, смотря в какой момент будут они связаны и какой тип соединения будет использован.

PS хотя конечно не стоит так делать с потоками - потоки этого не любят, ну или по крайней мере, не одобряют.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #23 : Февраль 13, 2016, 17:27 »

Блокировка происходит в модели. Пока там мутекс не освобождён стоит всё. И paint вызывает data, который ставит Mutex и который отдаёт данные. В один момент времени могут быть отданы данные, или же изменены данные.
Это не спасает т.к. QModelIndex мог быть получен ДО изменения данных. Внимательно прочитайте объяснения в посте #19
Записан
Bepec
Гость
« Ответ #24 : Февраль 13, 2016, 17:39 »

QModelIndex это просто циферки row и column для вызова функции Data или Remove или Insert.
Ставим мутекс в Data и мы защищены от ВСЕХ читающих.
Мутексы поставленные в ф-ции запроса, добавления, изменения и удаления данных защищают данные.

В том и суть реализации model-View, все данные читающие получают из стандартных функций, которые мы можем защитить мутексами.

PS сообщение прочитал, нового не узнал. По сути всё сводится - невалидный индекс в функции data, защищённой мутексом и проверкой индекса на валидность. Т.е. мутекс не даст конфликтовать при изменениях, а проверка на валидность не допустит обращения к несуществующим данным.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #25 : Февраль 13, 2016, 18:18 »

QModelIndex это просто циферки row и column для вызова функции Data или Remove или Insert.
Ставим мутекс в Data и мы защищены от ВСЕХ читающих.
Нет. Пусть рисуется напр 5-я строка (делегат получил QModelIndex с row = 5). Мутекс модели свободен - ведь никаких обращений к модели пока нет. Именно в этот злосчастный момент др нитка захватила мутекс, грохнула строки, освободила мутекс. И когда рисовальщик наконец полезет в модель - там 5-й строки-то уже нет (или вместо нее другая).
Записан
Bepec
Гость
« Ответ #26 : Февраль 13, 2016, 18:26 »

1) удаляется 5 строка.
2) Проходит захват мутекса делегатом для отрисовки 5 строки.
3) Проходит проверка на валидность индекса. На этой части он получает отлуп - пятой строки уже не существует и её удаление произведено корректно.
4) View получает QVariant().
5) Отрисовывает пустой поле.
6) Тут приходит сигнал об удалении в модели.
7) View удаляет ненужную строку.
Крутой Работа завершена корректно, пользователь увидел лишь удаление строки.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #27 : Февраль 14, 2016, 10:15 »

3) Проходит проверка на валидность индекса. На этой части он получает отлуп - пятой строки уже не существует и её удаление произведено корректно.
Без комментариев  Улыбающийся
Записан
Bepec
Гость
« Ответ #28 : Февраль 14, 2016, 12:15 »

Мм?
Вы хотите сказать, что переопределяя метод data(), проверку на валидность индекса в контейнере делать не надо? Пусть даже топорным
Код:
if (massive.size() >= index.row())
return QVariant();
Или же вы никогда не проверяете наличие яблок в пакете, беря яблоко? Веселый
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #29 : Февраль 14, 2016, 12:45 »

Или же вы никогда не проверяете наличие яблок в пакете, беря яблоко? Веселый
Я там новое голосование создал, там потренируйтесь Улыбающийся Здесь уже тема себя исчерпала
Записан
Страниц: 1 [2] 3   Вверх
  Печать  
 
Перейти в:  


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