Название: Сигнал, и его обработка во время выполнения другой функции, равно сегфолт Отправлено: xintrea от Декабрь 14, 2008, 22:52 Здравствуйте!
Тут у меня трудности с пониманием как работает Qt. Раньше я думал, что в Qt имеется общий программный цикл, в его начале обрабатываются сигналы-слоты, потом все объекты, причем обработку объекта прервать никак нельзя. Оказывается, это не так. Есть приложение, в котором есть QTreeView и всякие другие элементы управления. В QTreeView в методе удаления ветки имею такой код Код
А сегфолт получаю вот каким образом. Если в удаляемой ветке много подветок (при удалении веток происходит удаление фалов с резервным копированием), процедура удаления растягивается на секунду-другую. И вот если в этот промежуток успеть ткнуть мышкой на какую-либо другую ветку, или на какую-либо кнопку управления, то получим сегфолт. В логе видно следующее Код: Before delete item то есть по логу видно, что обработка слота началась в середине выполнения метода удаления ветки, т.к. Arter delete item не появилось, да и лог выполнения метода прервался логом обработки слота. Как то мне это мало нравится, ибо оказывается, что впринципе порушить Qt программу можно быстро кликая на какие-нибудь кнопки с взаимопересекающимися действиями. Получается, что при любых "атомарных" действиях, надо пробегать все дерево объектов, блокировать для каждого объекта сигналы через blockSignals(), а в конце действия снова обегать все объекты и включать сигналы. Отключать все сигналы нужно потому, что в крупной системе сложно отследить, какие действия могут повлиять друг на друга при взаимном выполнении. Однако, в примерах я нигде подобное отключение сигналов не видел. Может я что-то делаю не так? Может надо при сборке указывать какие-то ключи чтоб отключать многопоточность? Хотя, проц уменя одноядерный, реального распарраллеливания нет... Вообще, как народ борется с такой проблемой? Вручную следят за всем кодом и отклчают слоты в действиях, которые при одновременном выполнении могут дать сбой? Название: Re: Сигнал, и его обработка во время выполнения другой функции, равно сегфолт Отправлено: KADABRA от Декабрь 14, 2008, 23:28 Программа однопоточная?
Название: Re: Сигнал, и его обработка во время выполнения другой функции, равно сегфолт Отправлено: ритт от Декабрь 14, 2008, 23:31 код покажи. хрен угадаешь что у тебя в removeRow
Название: Re: Сигнал, и его обработка во время выполнения другой функции, равно сегфолт Отправлено: xintrea от Декабрь 14, 2008, 23:41 Название: Re: Сигнал, и его обработка во время выполнения другой функции, равно сегфолт Отправлено: xintrea от Декабрь 14, 2008, 23:49 код покажи. хрен угадаешь что у тебя в removeRow У меня в removeRow() ничего, это часть Qt. Хотя постепенно выяснил, что этот метод в свою очередь вызывает removeRows() модели. Это виртуальный метод, котрый переопределяется. Его код аналогичен до символа коду из примера /examples/itemviews/editabletreemodel. Код
Да и сама программа, во всяком случае часть, отвечающая за дерево, практически построена на примере editabletreemodel. Название: Re: Сигнал, и его обработка во время выполнения другой функции, равно сегфолт Отправлено: xintrea от Декабрь 14, 2008, 23:59 Гуру, скажите как минимум, прерывание выполнение метода слотом - это нормально для Qt, так и должно быть?
Зыж: никаких многопоточных вещей не использую. Компилирую прогу командами qmake project.pro, потом make. Qt 4.4.1, Linux. Название: Re: Сигнал, и его обработка во время выполнения другой функции, равно сегфолт Отправлено: pastor от Декабрь 15, 2008, 00:12 Цитировать Recordtable tools update <--------------- Это началась обработка слота Каким образом вызывается этот слот? Название: Re: Сигнал, и его обработка во время выполнения другой функции, равно сегфолт Отправлено: xintrea от Декабрь 15, 2008, 00:41 Немного поясню. В программе есть список QListView (имя объекта recordview). Этот список меняется при клике на ветку QTreeView (имя объекта knowtree). У списка есть кнопки управления, которые должны обновляться при изменении содержимого (пустой список - одни кнопки, засветка в начале списка - другие кнопки, засветка посередине списка - третий набор конопок, засветка в конце списка - четвертый и т.д.)
Этот слот (выдащий строку "Recordtable tools update"), который может вмешаться в работу удаления ветки, называется tools_update() Он вызывается двумя способами. 1. Просто через connect для QListView recordview. Код
2. Есть прямой вызов tools_update() из слота on_knowtree_clicked(). Этот слот активизируется так Код
Всё, больше нигде никакой работы с tools_update() не происходит. Название: Re: Сигнал, и его обработка во время выполнения другой функции, равно сегфолт Отправлено: ритт от Декабрь 15, 2008, 02:18 Цитировать Before delete item Recordtable tools update <--------------- а это что началось? Try delete record num 2 table count 3 Remove dir "mytetradata/base/0000000388" start Move file from "mytetradata/base/0000000388/text.txt" to "mytetradata/trash/0000000686_text.txt" Try delete directory "mytetradata/base/0000000388" Directory "mytetradata/base/0000000388" delete succesfull Recordtable tools update <--------------- Это началась обработка слота In function recordview_select() Save current record text() ASSERT failure in QList<T>::at: "index out of range", file /usr/local/Trolltech/Qt-4.4.1/include/QtCore/qlist.h, line 393 Aborted (core dumped) попробуй закомментировать код в tools_update. и было бы неплохо увидеть код on_knowtree_clicked и tools_update Название: Re: Сигнал, и его обработка во время выполнения другой функции, равно сегфолт Отправлено: Sergeich от Декабрь 15, 2008, 03:38 У троллей в лабах есть тесты для модели, поробуй прогнать через них: http://labs.trolltech.com/page/Projects/Itemview/Modeltest
Название: Re: Сигнал, и его обработка во время выполнения другой функции, равно сегфолт Отправлено: Alex Custov от Декабрь 15, 2008, 08:32 очевидно, что последующие события после removeRow (как его результат) выполняются асинхронно. Слот не прерывается, но он даёт время на обработку событий типа кликов. Заблокируй необходимые сигналы на время работы removeRow.
Название: Re: Сигнал, и его обработка во время выполнения другой функции, равно сегфолт Отправлено: Tonal от Декабрь 15, 2008, 08:53 В Qt магии нет. Поэтому никто твой код прерывать не будет. :)
Но похожий на "прерывание" эффект может появится несколькими способами: 1. При испускании сигнала Qt по умолчанию вызывает слоты-обработчики сразу как обычный вызов. Только если объект обработчик находится в другом потоке, или если явно указано, вызов ставится в очередь. 2. При посылки события с помощью sendEvent обработчик вызывается сразу же. 3. При явном вызове rocessEvents или sendPostedEvents Ну и я обычно дизаблю всё главное окно на время "атомарных" действий. Ну или диалог из инициировавший. Название: Re: Сигнал, и его обработка во время выполнения другой функции, равно сегфолт Отправлено: BRE от Декабрь 15, 2008, 08:58 Код
Название: Re: Сигнал, и его обработка во время выполнения другой функции, равно сегфолт Отправлено: SABROG от Декабрь 15, 2008, 09:34 Попробуй флаг Qt::QueuedConnection передавать в метод connect. Тогда слоты будут вызываться при возвращении в основной eventLoop.
Название: Re: Сигнал, и его обработка во время выполнения другой функции, равно сегфолт Отправлено: Tonal от Декабрь 15, 2008, 11:23 2 SABROG У автора немного другая проблема - во время долгого вычисления можно произвести действие в итерфейсе (выбрать другую ветку дерева) из за которого вычисление может порушиться.
В этом случае либо дизаблить/замараживать интерфейс, либо максимально отвязываться от UI - т.е. пришло событие, собираем всю нужную инфу в отдельную структуру и дальше работаем именно с ней а не с виджетами. Название: Re: Сигнал, и его обработка во время выполнения другой функции, равно сегфолт Отправлено: SABROG от Декабрь 15, 2008, 12:20 QFileSystemModel не используется случайно ?
Код
Название: Re: Сигнал, и его обработка во время выполнения другой функции, равно сегфолт Отправлено: xintrea от Декабрь 15, 2008, 13:54 Ну и я обычно дизаблю всё главное окно на время "атомарных" действий. А подробнее, что имеется в виду под дизаблингом главного окна? Ну или диалог из инициировавший. Диалог, их (атомарные действия) инициировавший? А как его дизаблите? Так же как и главное окно? Название: Re: Сигнал, и его обработка во время выполнения другой функции, равно сегфолт Отправлено: SABROG от Декабрь 15, 2008, 14:19 Вероятно так:
Код
Название: Re: Сигнал, и его обработка во время выполнения другой функции, равно сегфолт Отправлено: xintrea от Декабрь 15, 2008, 14:24 В доке не уточнен момент.
При вызове setDisabled(true) конкретного виджета, будут ли заблокированы input events для всех вижджетов, входящих в блокируемый виджет? Название: Re: Сигнал, и его обработка во время выполнения другой функции, равно сегфолт Отправлено: SABROG от Декабрь 15, 2008, 15:02 В доке не уточнен момент. При вызове setDisabled(true) конкретного виджета, будут ли заблокированы input events для всех вижджетов, входящих в блокируемый виджет? Да, все дочерние виджеты отрубятся тоже, в миг посереют. Название: Re: Сигнал, и его обработка во время выполнения другой функции, равно сегфолт Отправлено: xintrea от Декабрь 15, 2008, 21:37 У меня что-то с глазами, или действительно в этой ветке удалена мессага кого-то из админов про blockSignals? Хотелось бы еще раз увидеть этот код, не успел я его толком посмотреть.
Название: Re: Сигнал, и его обработка во время выполнения другой функции, равно сегфолт Отправлено: spirit от Декабрь 15, 2008, 21:52 Код
Название: Re: Сигнал, и его обработка во время выполнения другой функции, равно сегфолт Отправлено: xintrea от Декабрь 15, 2008, 23:05 В общем, нашел я в чем проблема. Проблема возникает в двух случаях
1. Из-за незаблокированного интерфейса (поборол). То есть если в процессе удаления успеть кнуть на другую ветку, получим гарантированный сегфолт. Проблему решил командами Код
не знаю, может и избыточно, можно былоб обойтись только setDisabled() setEnabled(), но в доке по этим методам про блокировку сигналов ничего не сказано, только про "события". 2. Из-за переустановки сигналов при смене модели для QListView (побороть не смог). Когда меняется ветка в QTreeView, модель в QListView заменяется через метод setModel(). Сразу после этой команды приходится связывать сигналы Код
Это нужно делать, так как при смене модели связка сигналов для selection model удаляется, о чем написано в доке и проверено на практике Цитировать Note that, if you call setModel() after this function, the given selectionModel will be replaced by one created by the view. То есть, если сигналы определить один раз в инициализации всего виджета, то при смене модели они перестанут работать. Поэтому их и приходится заново прописывать после смены модели. Дело осложняется тем, что в глубине процедуры удаления веток происходит вызов смены модели для QListView (когда перебираются удаляемые подветки). И если мы перед процедурой удаления заблокировали все connection, то внутри процедуры удаления они заново создаются. Потом вызывается слот (при удалении строк в QListView) в получается сегфолт. Я думал, что mainwindow->setDisabled(true) заблокирует глобально все. Т.е. просто не будут ходить сигналы. И потому вновьсозданные сигналы не будут работать. Но оказываются, они работают... Вопрос: как с минимальными потерями выйти из этой ситуации? Так, чтобы и идеологически правильно, и код тоннами не перелопачивать? ЗЫЖ: В общем, я с самого начала проектировал прогу не зная таких особенностей. Теперь не преццтавляю что делать - переделывать всю логику взаимодействия виджетов - это прощще весь проект переписать. У меня действительно сильно завязаны функции представления данных на экране и функции работы с данными, одно вызывает другое, и я слабо понимаю, как по-другому можно делать пользовательский интерфейс (а я раньше их и не проектировал). Название: Re: Сигнал, и его обработка во время выполнения другой функции, равно сегфолт Отправлено: ритт от Декабрь 15, 2008, 23:47 Цитировать Дело осложняется тем, что в глубине процедуры удаления веток происходит вызов смены модели для QListView (когда перебираются удаляемые подветки). И если мы перед процедурой удаления заблокировали все connection, то внутри процедуры удаления они заново создаются. Потом вызывается слот (при удалении строк в QListView) в получается сегфолт. где? имя файла и номер строчки можно?или это личная прихоть? Название: Re: Сигнал, и его обработка во время выполнения другой функции, равно сегфолт Отправлено: xintrea от Декабрь 16, 2008, 00:30 Цитировать Дело осложняется тем, что в глубине процедуры удаления веток происходит вызов смены модели для QListView (когда перебираются удаляемые подветки). И если мы перед процедурой удаления заблокировали все connection, то внутри процедуры удаления они заново создаются. Потом вызывается слот (при удалении строк в QListView) в получается сегфолт. где? имя файла и номер строчки можно?или это личная прихоть? Ну да, это личная прихоть, так организована программа. Когда в дереве удаляется ветка, пробегаются все подветки. Для каждой ветки-подветки вызывается процедура удаления данных из строк, представленных в QListView. При смене подветки, в QListView вставляется новая модель. При этом приходится создавать сигналы, ну и имеем то что имеем. Я конечно могу сделать глобальный флаг, типа "идет атомарная операция", и в эти моменты в тех местах где "динамически" создаются connection, их не создавать (всеравно они создастья сами потом при пользовании интерфейса. Хотя, чтоб они создались, возможно придется что-то один раз передергивать). Это не самый лучший метод, хотя работать будет. Поэтому, я хочу узнать более правильный метод. Название: Re: Сигнал, и его обработка во время выполнения другой функции, равно сегфолт Отправлено: ритт от Декабрь 16, 2008, 00:39 Поэтому, я хочу узнать более правильный метод. не подменяй модель, пока вьюха обрабатывает её айтемы... Название: Re: Сигнал, и его обработка во время выполнения другой функции, равно сегфолт Отправлено: xintrea от Декабрь 16, 2008, 01:00 не подменяй модель, пока вьюха обрабатывает её айтемы... О, это мысль. А каким методом узнавать что вьюха обрабатывает айтемы? Название: Re: Сигнал, и его обработка во время выполнения другой функции, равно сегфолт Отправлено: ритт от Декабрь 16, 2008, 01:39 перефразирую: "не подменяй модель"
представь, что модель - это указатель на буффер, а вьюха - цикл, в котором используется данный указатель (для перебота элементов, например). что случится, если во время модификации буффера ты вдруг подменишь указатель на какой-нибудь другой буффер (а если ещё и размер/тип данных отличается)? работай с моделью как с источником данных, а вьюха пусть выполняет своё предназначение - визуализацию данных, навигацию и т.д. Название: Re: Сигнал, и его обработка во время выполнения другой функции, равно сегфолт Отправлено: BRE от Декабрь 16, 2008, 09:02 Не меняй модель. Сделай в ней слот, который будет ее перестраивать в зависимости от выбранной ветки. Свяжи сигнал изменения ветки в knowtree с этим сигналом.
При смене ветки, модель для recordview настроится для отображения выбранной ветки, и сделает emit layoutChanged(), recordview ее перечитает и выведет на экран. Название: Re: Сигнал, и его обработка во время выполнения другой функции, равно сегфолт Отправлено: Tonal от Декабрь 16, 2008, 10:00 В любой нормальной оконной системе отключение (запрещение? дизабление?) не отменяет все события.
Оно нужно чтобы информировать пользователя о том что сейчас сюда тыкать не нужно. :) Отключённое окно можно сворачивать/разворачивать, оно правильно отрисовывается, работают таймеры и т.д. По поводу второго глюка: согласен с BRE. Да и вообще по хорошему, нужно стараться как можно больше развязать GUI и свои данные. Т.е. всякие виджеты и модели использовать только для отображения и получения событий от пользователя. А при получении событий сразу же формировать необходимый набор параметров и звать уже свои функции из своих классов данных. Так при очередной смене версий Qt или самого фреймворка понадобиться переписать только GUI-часть, а логика данных останется. :) Да, есть ещё "быстрое" решение твоей проблемы - без переработки дизайна. :) Вынеси всю настройку ListView-а в отдельную функцию и вызови её потом - после окончания всей обработки. Удобно делать это с помощью QTimer::singleShot с небольшим таймоутом. Название: Re: Сигнал, и его обработка во время выполнения другой функции, равно сегфолт Отправлено: xintrea от Декабрь 16, 2008, 14:54 Всем спасибо за советы, сделаю, наверно, как BRE сказал.
Название: Re: Сигнал, и его обработка во время выполнения другой функции, равно сегфолт Отправлено: xintrea от Декабрь 19, 2008, 14:14 Фух, ерунда какая-то получается.
Концепция "не менять модель для QListView, а перестраивать ее" упирается вот во что. К вьюхе (QListView) виджет прикручивает модель. Виджет может влиять на модель - по своим кнопкам вызывать методы вставки, замены, удаления данных в модели. А вьюха все эти изменения показывает. Нам нужно перестроить модель. Что для этого надо сделать? Вначале надо удалить строки из модели, и понапихать новых строк из новой пришедшей для замены модели. Что при этом произойдет? В моей программе в момент удаления строк из модели, они действительно удалятся, т.е. удаление будет сопровождаться удалением хранимых данных на винте. Потом при напихивании новых строк, произойдет, грубо говоря, копирование данных - данные из модели новой отображаемой ветки понапихаются в модель предыдущей ветки. В момент "напихивания" модель тоже будет все записывать на винт. То есть, надо делать как-то по-другому. Но как? Вроде вьюха занимается только тем чем ей положено - показывает данные. Модель тоже занимается тем чем ей положено - реагирует на команды виджета и управляет данными. Что я блин не так спроектировал? Название: Re: Сигнал, и его обработка во время выполнения другой функции, равно сегфолт Отправлено: BRE от Декабрь 19, 2008, 17:14 Нам нужно перестроить модель. Что для этого надо сделать? Вначале надо удалить строки из модели, и понапихать новых строк из новой пришедшей для замены модели. Ничего в модели удалять не надо, нужно сделать так, что бы в следующий раз она для view'а возвращала те данные, которые необходимы для отображения в текущий момент. Изменился текущий элемент в treeView, мы известили об этом модель, модель начала возвращать для view данные для текущего элемента.Или как вариант, можно сделать одну модель со всей работай с данными, а для вывода использовать прокси-модель. Название: Re: Сигнал, и его обработка во время выполнения другой функции, равно сегфолт Отправлено: xintrea от Декабрь 19, 2008, 21:12 Ничего в модели удалять не надо, нужно сделать так, что бы в следующий раз она для view'а возвращала те данные, которые необходимы для отображения в текущий момент. Изменился текущий элемент в treeView, мы известили об этом модель, модель начала возвращать для view данные для текущего элемента. Или как вариант, можно сделать одну модель со всей работай с данными, а для вывода использовать прокси-модель. У меня, при открытии программы, создается и заполняется (из XML) дерево итемов для QTreeView. В каждом QTreeView итеме хранится модель списка QListView (которае тоже из XML заполняется). То есть, в экземплярах модели для QListView хранятся данные. (Ничего плохого в этом не вижу, то есть хранимые данные и методы работы с ними обобщены в одном классе). В данный момент, когда меняется ветка, просто передается указатель на модель для новой открываемой ветки. Модели для QListView уже содержат нужные данные, заполненные в нее при старте программы. То есть, при такой схеме, "сделать так, что бы в следующий раз модель для view'а возвращала те данные, которые необходимы для отображения в текущий момент" видимо не получится. Правильно ли я понимаю, что в такой ситуации остается только два варианта - 1. решение с прокси-моделью, 2. переделывать всю структуру приложения ? Название: Re: Сигнал, и его обработка во время выполнения другой функции, равно сегфолт Отправлено: ритт от Декабрь 19, 2008, 21:41 удаляй строки, данные удалять не надо. это плохая практика - на каждоую манипуляцию дёргать необратимые действия...
сделай примерно так: пусть метод удаления данных/строк (например, remove(...)) вместо физического удаления просто помечает строку на удаление и скрывает её из вьюхи (removeRows(...) в самой модели), а потом на commit() уже выполняй запланированные действия с данными. это на мой взгляд более правильный подход. либо чуть иначе: в своей модели переопредели removeRows(...) для физического удаления данных под строкой, а при синхронизации с другой моделью (aka append(),prepend(),substract() модели на модель) используй removeRows(...) суперкласса, что не приведёт к физическому удалению данных. Название: Re: Сигнал, и его обработка во время выполнения другой функции, равно сегфолт Отправлено: ритт от Декабрь 19, 2008, 21:42 > В каждом QTreeView итеме хранится модель
некошерно Название: Re: Сигнал, и его обработка во время выполнения другой функции, равно сегфолт Отправлено: BRE от Декабрь 19, 2008, 22:28 У меня, при открытии программы, создается и заполняется (из XML) дерево итемов для QTreeView. В каждом QTreeView итеме хранится модель списка QListView (которае тоже из XML заполняется). То есть, в экземплярах модели для QListView хранятся данные. (Ничего плохого в этом не вижу, то есть хранимые данные и методы работы с ними обобщены в одном классе). Пусть в каждом QTreeView-итеме храниться не модель, а твоя струтура данных. Вот эта структура и будет передаваться в модель, а модель будет из нее брать данные и отдовать viewer'у.Название: Re: Сигнал, и его обработка во время выполнения другой функции, равно сегфолт Отправлено: ритт от Декабрь 19, 2008, 22:53 указатель или ссылка на структуру данных, если уж на то пошло...
а ещё лучше - указатель на источник данных и параметры выобрки - не придётся строить все структуры в момент создания дерева (если источник неповоротливый) Название: Re: Сигнал, и его обработка во время выполнения другой функции, равно сегфолт Отправлено: BRE от Декабрь 19, 2008, 23:10 указатель или ссылка на структуру данных, если уж на то пошло... Ну, xintrea вроде не идиот, что бы ему все так подробно расписывать, думаю он бы это и сам понял. ;) |