Название: Частое добавление и удаление строки в QAbstractTableModel Отправлено: YvenTitan от Февраль 11, 2016, 15:51 Добрый день!
Стоит задача сделать таблицу обновлений с помощью QAbstractTableModel. В небольшом тестовом примере таблица из 4 строк. В нем в отдельном потоке я раз 1 милисекунду добавляю в конец таблицы одну строку с помощью insertRows и одну строку удаляю из ее начала(removeRows). В итоге через 10-60 секунд работы приложение вылетает. Если добавлять и удалять строки раз в 10 милисекунд, то работает нормально. Как сделать, чтобы приложение работало стабильно? Название: Re: Частое добавление и удаление строки в QAbstractTableModel Отправлено: Bepec от Февраль 11, 2016, 16:30 Перестать пороть чушь и сделать нормальную архитектуру приложения.
Название: Re: Частое добавление и удаление строки в QAbstractTableModel Отправлено: YvenTitan от Февраль 11, 2016, 16:34 Можно по конкретнее, что именно исправить
Вылетает с ошибкой: ASSERT failure in QList<T>::at "index out of range" file qlist.h This application has requested the Runtime to terminate it in an unusual way Название: Re: Частое добавление и удаление строки в QAbstractTableModel Отправлено: gil9red от Февраль 11, 2016, 20:20 Можно по конкретнее, что именно исправить Вылетает с ошибкой: ASSERT failure in QList<T>::at "index out of range" file qlist.h This application has requested the Runtime to terminate it in an unusual way Выход за пределы диапазона. Вы у списка запрашиваете элемент, индекс которого нет. Название: Re: Частое добавление и удаление строки в QAbstractTableModel Отправлено: Bepec от Февраль 11, 2016, 20:37 Пороть чушь - про добавление и удаление строки с интервалом 1мс.
А так если у вас проблемы в КОДЕ - покажите КОД. Название: Re: Частое добавление и удаление строки в QAbstractTableModel Отправлено: Old от Февраль 11, 2016, 20:48 Пороть чушь - про добавление и удаление строки с интервалом 1мс. А что в этом страшного?А так если у вас проблемы в КОДЕ - покажите КОД. Так у ТС проблема в коде или архитектуре?Название: Re: Частое добавление и удаление строки в QAbstractTableModel Отправлено: Old от Февраль 11, 2016, 21:11 Можно по конкретнее, что именно исправить Нельзя так просто работать со списками из разных потоков. Нужно использовать средств синхронизации.Название: Re: Частое добавление и удаление строки в QAbstractTableModel Отправлено: Bepec от Февраль 11, 2016, 21:45 Таки не заметил прикрепленного архива, извиняюсь.
to Old: да, таки проблема в архитектуре и как следствие реализация в коде. И я тоже склоняюсь, что виноваты потоки. Низя обращаться к простому списку из двух разных потоков. А если и обращаетесь, то мутексами защищайте чтоли. Название: Re: Частое добавление и удаление строки в QAbstractTableModel Отправлено: Igors от Февраль 12, 2016, 07:49 Хммм... а что и как засисять? Налепить QMutexLocker во всех методах? Это выглядит уродливо но ничего не гарантирует - могут найтись неперекрытые базовые методы, а то и вообще заклинит
Название: Re: Частое добавление и удаление строки в QAbstractTableModel Отправлено: Old от Февраль 12, 2016, 08:00 могут найтись неперекрытые базовые методы, а то и вообще заклинит Что значит "могут найтись": небыло-небыло, а потом раз и нашлись? Нужно постараться не забыть перекрыть.А вообще утверждать работоспособность модели в не gui-потоке я не могу, все никак руки не дойдут попробовать. Я долгие операции выполняю в рабочих нитках, и по сигналу добавляю информацию в модель уже из контексте gui-нитки. Название: Re: Частое добавление и удаление строки в QAbstractTableModel Отправлено: Bepec от Февраль 12, 2016, 09:00 Не найдется никаких базовых методов. Ибо контейнер добавлен исключительно ТСсом и все методы где он используются описаны опять таки в классе ТСса.
PS да, просто мутекс локеры натыкать и всё становится хорошо. Название: Re: Частое добавление и удаление строки в QAbstractTableModel Отправлено: Igors от Февраль 12, 2016, 09:11 Ладно, попробуем, ну не с мутексами конечно. В аттаче измененные файлы. Вроде "не летит", но увы - это еще ничего не значит.
Не найдется... СвободенНазвание: Re: Частое добавление и удаление строки в QAbstractTableModel Отправлено: YvenTitan от Февраль 12, 2016, 09:22 В реальной задаче добавлять и удалять строку надо чаще, там приходит много обновлений. Это связано с тем, что они приходят с датчиков. Это простой пример, чтобы немного понятно было.
Мьютексы я пробовал делать, но не помогало. Если кто конкретно скажет, куда их поставить, то буду благодарен. В данном тестовом примере поможет qSleep(1) после beginInsertRows и removeInsertRows, но в реальном примере это тоже бессильно. Мне кажется, что проблема в следующем. При вызове функции beginInsertRows испускается сигнал rowsAboutToBeInserted(), по нему объект QTableView выполняет в потоке вставку строк в себя. При endInsertRows испускается rowsInserted. Аналогично при вызове beginRemoveRows выделяется сигнал rowsAboutToBeRemoved и в потоке QTableView удаляет из View строку. Как синхронизировать эти потоки - для меня главный вопрос. Если где-то неправ - поправьте. Название: Re: Частое добавление и удаление строки в QAbstractTableModel Отправлено: Bepec от Февраль 12, 2016, 09:32 Система сигнал слотов сама разбирает проблему с потоками, хотя в вашем случае хзкак оно работает :D
Если поставить QMutexLocker в функции data, insertRows, removeRows, то в данном конкретном проекте вылеты прекращаются. to Igors: пора бы знать, что если никто не знает об объекте, то и обращаться к нему не могёт, так что "найтись" не могут моменты. Разве что сам напишешь. Название: Re: Частое добавление и удаление строки в QAbstractTableModel Отправлено: Old от Февраль 12, 2016, 09:32 В реальной задаче добавлять и удалять строку надо чаще, там приходит много обновлений. Это связано с тем, что они приходят с датчиков. Это простой пример, чтобы немного понятно было. Не очень понятно, для чего вы всю модель переместили в контекст другой нитки.Лучше из другой нитки эмитить сигнал, когда появились данные для вставки, а слот из gui-нитки уже будет вставлять их в модель (и выкидывать устаревшие). Название: Re: Частое добавление и удаление строки в QAbstractTableModel Отправлено: Igors от Февраль 12, 2016, 10:03 Мне кажется, что проблема в следующем. При вызове функции beginInsertRows испускается сигнал rowsAboutToBeInserted(), по нему объект QTableView выполняет в потоке вставку строк в себя. При endInsertRows испускается rowsInserted. Аналогично при вызове beginRemoveRows выделяется сигнал rowsAboutToBeRemoved и в потоке QTableView удаляет из View строку. Как синхронизировать эти потоки - для меня главный вопрос. Не исключено что и "никак". Напр где-то "в недрах" есть код типаКод Если рабочая нитка в это время меняет число строк - вылет неизбежен. Нужно залочить код выше, но это может оказаться слишком трудным или вообще недостижимым. И никто не гарантирует что такой код не появится в след версии Qt. С др стороны если сигналы с датчиков приходят интенсивно - какой смысл дергать UI на каждый чих? Логичнее накапливать/буферировать изменения а потом их скопом применить. Мьютексы я пробовал делать, но не помогало. Если кто конкретно скажет, куда их поставить На paint вьюхи точно нужен. Но я бы с этим вообще не связывался - это ненадежно Название: Re: Частое добавление и удаление строки в QAbstractTableModel Отправлено: Bepec от Февраль 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 может повлиять на данные в модели? :P Название: Re: Частое добавление и удаление строки в QAbstractTableModel Отправлено: Igors от Февраль 12, 2016, 11:41 PS мне вот лично интересно как paint View может повлиять на данные в модели? :P Еще как повлияет, правда наоборот :) Мне даже не хочется Вас пинать, все равно без толку, ничему не научитесь Название: Re: Частое добавление и удаление строки в QAbstractTableModel Отправлено: YvenTitan от Февраль 12, 2016, 14:40 Спасибо, Igors. Ваш код помог. Правда как только я вместо QAbstractTableModel стал использовать QSortFilterModel, то проблема вернулась, несмотря на то, что я перед функцией filterAcceptRow ставлю CScopedLock lock(m_Lock).
Название: Re: Частое добавление и удаление строки в QAbstractTableModel Отправлено: Igors от Февраль 12, 2016, 15:05 Спасибо, Igors. Ваш код помог. Правда как только я вместо QAbstractTableModel стал использовать QSortFilterModel, то проблема вернулась, несмотря на то, что я перед функцией filterAcceptRow ставлю CScopedLock lock(m_Lock). Простой пример тоже должен вылететь, пусть и через длительное время. Дело в том что лочить надо обоих (читающего и пишущего). Пример:Код Пусть пока рабочая нитка не обновляла модель. Все хорошо, пришел нормальный QModelIndex. И тут в точке "пробой" UI нитка заснула, а рабочая наоборот проснулась и грохнула строки. Затем главная просыпается, лезет model->data() по индексу, но он-то уже невалиден. Без разницы MyDelegate или стандартный Qt Поэтому придется лочить paint целиком, sizeHint и вообще всех методы работающие с моделью в цикле. Сигналы с параметрами QModelIndex тоже станут невалидны. И даже если удастся обеспечить все локи - попадаем в др беду. Напр если удаление интенсивно - залоченному paint трудно прорваться, UI будет подвисать. Поэтому думается что работа с моделью в др нитке - принципиально неверное решение Название: Re: Частое добавление и удаление строки в QAbstractTableModel Отправлено: Bepec от Февраль 12, 2016, 22:17 А теперь добавляем радость, что там когда грохнули данные стоит мутекс и он блокирует такую ситуацию :D Igors вы пытаетесь доказать, что используя защищённые мутексами функции для работы с данными можно порушить стек?
Просто надо пользоваться функциями модели, защищёнными мутексами и будет всё хорошо. Мутексы гораздо быстрее обновления ui. Хотя конечно зависит от нагрузки. PS ну если конечно написать model->m_rowList[1], то будет вылет. Название: Re: Частое добавление и удаление строки в QAbstractTableModel Отправлено: Igors от Февраль 13, 2016, 07:53 А теперь добавляем радость, что там когда грохнули данные стоит мутекс и он блокирует такую ситуацию :D Для блокировки нужно чтобы мутекс был захвачен UI ниткой еще до вызова MyDelеgate::paint. А так рабочая нитка его захватывает, удаляет строки и освобождает, оставляя UI в интересном положении. Название: Re: Частое добавление и удаление строки в QAbstractTableModel Отправлено: Bepec от Февраль 13, 2016, 17:11 Блокировка происходит в модели. Пока там мутекс не освобождён стоит всё. И paint вызывает data, который ставит Mutex и который отдаёт данные. В один момент времени могут быть отданы данные, или же изменены данные. А т.к. данные нетяжелые и скорость изменения данных очень высока, то пользователь не заметит даже разницы работы модели с мутексом или без.
Model и View связаны сигналами, которые сами разруливают проблемы с Queued connection. Хотя тут тоже вопрос, смотря в какой момент будут они связаны и какой тип соединения будет использован. PS хотя конечно не стоит так делать с потоками - потоки этого не любят, ну или по крайней мере, не одобряют. Название: Re: Частое добавление и удаление строки в QAbstractTableModel Отправлено: Igors от Февраль 13, 2016, 17:27 Блокировка происходит в модели. Пока там мутекс не освобождён стоит всё. И paint вызывает data, который ставит Mutex и который отдаёт данные. В один момент времени могут быть отданы данные, или же изменены данные. Это не спасает т.к. QModelIndex мог быть получен ДО изменения данных. Внимательно прочитайте объяснения в посте #19Название: Re: Частое добавление и удаление строки в QAbstractTableModel Отправлено: Bepec от Февраль 13, 2016, 17:39 QModelIndex это просто циферки row и column для вызова функции Data или Remove или Insert.
Ставим мутекс в Data и мы защищены от ВСЕХ читающих. Мутексы поставленные в ф-ции запроса, добавления, изменения и удаления данных защищают данные. В том и суть реализации model-View, все данные читающие получают из стандартных функций, которые мы можем защитить мутексами. PS сообщение прочитал, нового не узнал. По сути всё сводится - невалидный индекс в функции data, защищённой мутексом и проверкой индекса на валидность. Т.е. мутекс не даст конфликтовать при изменениях, а проверка на валидность не допустит обращения к несуществующим данным. Название: Re: Частое добавление и удаление строки в QAbstractTableModel Отправлено: Igors от Февраль 13, 2016, 18:18 QModelIndex это просто циферки row и column для вызова функции Data или Remove или Insert. Нет. Пусть рисуется напр 5-я строка (делегат получил QModelIndex с row = 5). Мутекс модели свободен - ведь никаких обращений к модели пока нет. Именно в этот злосчастный момент др нитка захватила мутекс, грохнула строки, освободила мутекс. И когда рисовальщик наконец полезет в модель - там 5-й строки-то уже нет (или вместо нее другая).Ставим мутекс в Data и мы защищены от ВСЕХ читающих. Название: Re: Частое добавление и удаление строки в QAbstractTableModel Отправлено: Bepec от Февраль 13, 2016, 18:26 1) удаляется 5 строка.
2) Проходит захват мутекса делегатом для отрисовки 5 строки. 3) Проходит проверка на валидность индекса. На этой части он получает отлуп - пятой строки уже не существует и её удаление произведено корректно. 4) View получает QVariant(). 5) Отрисовывает пустой поле. 6) Тут приходит сигнал об удалении в модели. 7) View удаляет ненужную строку. 8) Работа завершена корректно, пользователь увидел лишь удаление строки. Название: Re: Частое добавление и удаление строки в QAbstractTableModel Отправлено: Igors от Февраль 14, 2016, 10:15 3) Проходит проверка на валидность индекса. На этой части он получает отлуп - пятой строки уже не существует и её удаление произведено корректно. Без комментариев :)Название: Re: Частое добавление и удаление строки в QAbstractTableModel Отправлено: Bepec от Февраль 14, 2016, 12:15 Мм?
Вы хотите сказать, что переопределяя метод data(), проверку на валидность индекса в контейнере делать не надо? Пусть даже топорным Код: if (massive.size() >= index.row()) Название: Re: Частое добавление и удаление строки в QAbstractTableModel Отправлено: Igors от Февраль 14, 2016, 12:45 Или же вы никогда не проверяете наличие яблок в пакете, беря яблоко? :D Я там новое голосование создал, там потренируйтесь :) Здесь уже тема себя исчерпалаНазвание: Re: Частое добавление и удаление строки в QAbstractTableModel Отправлено: Bepec от Февраль 14, 2016, 13:35 Увы вы исчерпали свои отмазки в конкретно данном случае) Ну да бог с вами :D
Название: Re: Частое добавление и удаление строки в QAbstractTableModel Отправлено: Igors от Февраль 14, 2016, 13:46 Увы вы исчерпали свои отмазки в конкретно данном случае) Ну да бог с вами :D Напротив, я даже создал новую тему для Вашего обучения :) А здесь хороший, полезный топик, не будем его захламлятьНазвание: Re: Частое добавление и удаление строки в QAbstractTableModel Отправлено: Авварон от Февраль 14, 2016, 19:02 В данном случае Igors прав, может быть случай, когда количество рядов рассинхронизуется между моделью и вью. Это как если кидать beginInsertRows() после того, как данные поменялись - попробуйте, много интересного словите.
Название: Re: Частое добавление и удаление строки в QAbstractTableModel Отправлено: Bepec от Февраль 14, 2016, 19:30 Я специально пробовал (и неспециально) когда овладевал model-view. Стандартная связка modelView защищенная мутексами с собственным контейнером работает стабильно без всяких вылетов. Да, возможно мерцания, возможны лишние "левые" строки, но они были результатом неправильно отосланных сигналом - всем известных пар "begin insert remove update".
Собственно шаблон model-View Qt-шной полностью соответствует стандарту - model рулит данными в любой форме, view же НЕ МОЖЕТ вызвать ошибку в модели, если не пропущены элементарные проверки. Название: Re: Частое добавление и удаление строки в QAbstractTableModel Отправлено: YvenTitan от Февраль 15, 2016, 16:29 Может не совсем в тему.
Я попробовал отказаться от работы с моделью в другой нитке. Сделал так, что в отдельной нитке испускаются сигналы раз в миллисекунду. Результат остался тот же. Поэтому решил продолжить решение Igors. Добавил модель, которая наследуется от QSortFilterProxyModel. В итоге зависает при попытке удалить элемент, в методе removeRows, в строке m_rowList.removeAt(row). Со старой проблемой эта, скорее всего не связана. Ошибка не такая сложная, но за день не получилось ее решить. Если не сложно, можете подсказать, где может быть недочет? Название: Re: Частое добавление и удаление строки в QAbstractTableModel Отправлено: Igors от Февраль 15, 2016, 17:38 Добавил модель, которая наследуется от QSortFilterProxyModel. В итоге зависает при попытке удалить элемент, в методе removeRows, в строке m_rowList.removeAt(row). У меня не виснет а сразу летит. Использовал предложение Верес'а - пофиг ветер, если индекс невалиден, то data() возвращает пустой QVariant :)Код Так вроде "побежало", но такое решение считаю несерьезным и безграмотным, и Вам его не советую. Почему бы не сделать "обертку" для контейнера? Рабочая нитка не удаляет, а увеличивает счетчик удаленных (или хранит индексы удаленных если можно удалять в любом порядке). Добавлять добавляет но rowCount возвращает старое значение. Разумеется все это тоже защищено локами. В итоге обе нитки работают с 1 контейнером, но модель какое-то время показывает его старую копию. Потом (хоть по таймеру) главная нитка посылает самой себе сигнал по которому (опять-таки под защитой лока) делается removeRows, удаленные реально удаляются, и insertRows. Все совершенно легально, и (на первый взгляд) несложно Название: Re: Частое добавление и удаление строки в QAbstractTableModel Отправлено: Old от Февраль 15, 2016, 17:41 Сделал так, что в отдельной нитке испускаются сигналы раз в миллисекунду. Результат остался тот же. IMHO, лучше разобраться с этим вариантом. Выкладывайте ваш проект. Название: Re: Частое добавление и удаление строки в QAbstractTableModel Отправлено: YvenTitan от Февраль 16, 2016, 11:12 Спасибо, Igors. Мне этот метод тоже помог. Пока оставлю его, хоть он и "колхозный".
Old, выкладываю свой вариант с сигналами Название: Re: Частое добавление и удаление строки в QAbstractTableModel Отправлено: Old от Февраль 16, 2016, 17:55 Old, выкладываю свой вариант с сигналами Ну, вы особо ничего не изменили, по прежнему перемещаете модель в контекст другого потока...Сделайте класс Sensor, это будет имитатор сенсора. Создайте несколько объектов этого класса, пусть они будут выполняться в отдельных потоках и генерируют сигнал newData. Модель должна находится в контексте GUI-потока и иметь слот для модификации (добавление/удаление). Соедините сигналы сенсоров со слотом модели и все заработает. Желательно сразу продумать систему группировки строк: добавлять строки сразу пачками. Пользовать все равно не может увидить добавление строки раз в несколько миллисекунд, для него они будут добавляться пачками. |