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

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

Страниц: [1] 2 3   Вниз
  Печать  
Автор Тема: Сигнал, и его обработка во время выполнения другой функции, равно сегфолт  (Прочитано 22641 раз)
xintrea
Супер активный житель
*****
Offline Offline

Сообщений: 754



Просмотр профиля WWW
« : Декабрь 14, 2008, 22:52 »

Здравствуйте!


Тут у меня трудности с пониманием как работает Qt. Раньше я думал, что в Qt имеется общий программный цикл, в его начале обрабатываются сигналы-слоты, потом все объекты, причем обработку объекта прервать никак нельзя. Оказывается, это не так.

Есть приложение, в котором есть QTreeView и всякие другие элементы управления. В QTreeView в методе удаления ветки имею такой код

Код
C++ (Qt)
qDebug() << "Before delete item";
 
trmodel->removeRow(index.row(), index.parent());
 
qDebug() << "Arter delete item";

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

В логе видно следующее

Код:
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)

то есть по логу видно, что обработка слота началась в середине выполнения метода удаления ветки, т.к. Arter delete item не появилось, да и лог выполнения метода прервался логом обработки слота.

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

Получается, что при любых "атомарных" действиях, надо пробегать все дерево объектов, блокировать для каждого объекта сигналы через blockSignals(), а в конце действия снова обегать все объекты и включать сигналы. Отключать все сигналы нужно потому, что в крупной системе сложно отследить, какие действия могут повлиять друг на друга при взаимном выполнении.


Однако, в примерах я нигде подобное отключение сигналов не видел. Может я что-то делаю не так? Может надо при сборке указывать какие-то ключи чтоб отключать многопоточность? Хотя, проц уменя одноядерный, реального распарраллеливания нет... Вообще, как народ борется с такой проблемой? Вручную следят за всем кодом и отклчают слоты в действиях, которые при одновременном выполнении могут дать сбой?
Записан

Собираю информацию по крупицам
http://webhamster.ru
KADABRA
Гость
« Ответ #1 : Декабрь 14, 2008, 23:28 »

Программа однопоточная?
Записан
ритт
Гость
« Ответ #2 : Декабрь 14, 2008, 23:31 »

код покажи. хрен угадаешь что у тебя в removeRow
Записан
xintrea
Супер активный житель
*****
Offline Offline

Сообщений: 754



Просмотр профиля WWW
« Ответ #3 : Декабрь 14, 2008, 23:41 »

Программа однопоточная?

Да, программа однопоточная.
Записан

Собираю информацию по крупицам
http://webhamster.ru
xintrea
Супер активный житель
*****
Offline Offline

Сообщений: 754



Просмотр профиля WWW
« Ответ #4 : Декабрь 14, 2008, 23:49 »

код покажи. хрен угадаешь что у тебя в removeRow

У меня в removeRow() ничего, это часть Qt. Хотя постепенно выяснил, что этот метод в свою очередь вызывает removeRows() модели. Это виртуальный метод, котрый переопределяется. Его код аналогичен до символа коду из примера /examples/itemviews/editabletreemodel.

Код
C++ (Qt)
bool TreeModel::removeRows(int position, int rows, const QModelIndex &parent)
{
   TreeItem *parentItem = getItem(parent);
   bool success = true;
 
   beginRemoveRows(parent, position, position + rows - 1);
   success = parentItem->removeChildren(position, rows);
   endRemoveRows();
 
   return success;
}

Да и сама программа, во всяком случае часть, отвечающая за дерево, практически построена на примере editabletreemodel.
Записан

Собираю информацию по крупицам
http://webhamster.ru
xintrea
Супер активный житель
*****
Offline Offline

Сообщений: 754



Просмотр профиля WWW
« Ответ #5 : Декабрь 14, 2008, 23:59 »

Гуру, скажите как минимум, прерывание выполнение метода слотом - это нормально для Qt, так и должно быть?

Зыж: никаких многопоточных вещей не использую. Компилирую прогу командами qmake project.pro, потом make. Qt 4.4.1, Linux.
Записан

Собираю информацию по крупицам
http://webhamster.ru
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #6 : Декабрь 15, 2008, 00:12 »

Цитировать
Recordtable tools update <--------------- Это началась обработка слота

Каким образом вызывается этот слот?
Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
xintrea
Супер активный житель
*****
Offline Offline

Сообщений: 754



Просмотр профиля WWW
« Ответ #7 : Декабрь 15, 2008, 00:41 »

Немного поясню. В программе есть список QListView (имя объекта recordview). Этот список меняется при клике на ветку QTreeView (имя объекта knowtree). У списка есть кнопки управления, которые должны обновляться при изменении содержимого (пустой список - одни кнопки, засветка в начале списка - другие кнопки, засветка посередине списка - третий набор конопок, засветка в конце списка - четвертый и т.д.)


Этот слот (выдащий строку "Recordtable tools update"), который может вмешаться в работу удаления ветки, называется tools_update() Он вызывается двумя способами.


1. Просто через connect для QListView recordview.

Код
C++ (Qt)
// Сигналы для обновления панели инструментов
connect(recordview, SIGNAL(activated(const QModelIndex &)),
        this, SLOT(tools_update(void)));
connect(recordview, SIGNAL(clicked(const QModelIndex &)),
        this, SLOT(tools_update(void)));
connect(recordview, SIGNAL(doubleClicked(const QModelIndex &)),
        this, SLOT(tools_update(void)));
connect(recordview, SIGNAL(entered(const QModelIndex &)),
        this, SLOT(tools_update(void)));
connect(recordview, SIGNAL(pressed(const QModelIndex &)),
        this, SLOT(tools_update(void)));
connect(QApplication::clipboard(),SIGNAL(dataChanged()),
        this, SLOT(tools_update(void)));


2. Есть прямой вызов tools_update() из слота on_knowtree_clicked(). Этот слот активизируется так

Код
C++ (Qt)
// Сигнал что ветка выбрана мышкой
connect(knowtree,SIGNAL(pressed(const QModelIndex &)),
        this,SLOT(on_knowtree_clicked(const QModelIndex &)));
 
// Сигнал что ветка выбрана стрелками на клавиатуре
connect(knowtree->selectionModel(), SIGNAL(currentRowChanged (const QModelIndex&, const QModelIndex&)),
        this, SLOT(on_knowtree_clicked(const QModelIndex&)));


Всё, больше нигде никакой работы с tools_update() не происходит.
« Последнее редактирование: Декабрь 15, 2008, 00:44 от xintrea » Записан

Собираю информацию по крупицам
http://webhamster.ru
ритт
Гость
« Ответ #8 : Декабрь 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
Записан
Sergeich
Гость
« Ответ #9 : Декабрь 15, 2008, 03:38 »

У троллей в лабах есть тесты для модели, поробуй прогнать через них: http://labs.trolltech.com/page/Projects/Itemview/Modeltest
Записан
Alex Custov
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2063


Просмотр профиля
« Ответ #10 : Декабрь 15, 2008, 08:32 »

очевидно, что последующие события после removeRow (как его результат) выполняются асинхронно. Слот не прерывается, но он даёт время на обработку событий типа кликов. Заблокируй необходимые сигналы на время работы removeRow.
Записан
Tonal
Гость
« Ответ #11 : Декабрь 15, 2008, 08:53 »

В Qt магии нет. Поэтому никто твой код прерывать не будет. Улыбающийся
Но похожий на "прерывание" эффект может появится несколькими способами:
1. При испускании сигнала Qt по умолчанию вызывает слоты-обработчики сразу как обычный вызов.
Только если объект обработчик находится в другом потоке, или если явно указано, вызов ставится в очередь.
2. При посылки события с помощью sendEvent обработчик вызывается сразу же.
3. При явном вызове rocessEvents или sendPostedEvents

Ну и я обычно дизаблю всё главное окно на время "атомарных" действий.
Ну или диалог из инициировавший.
Записан
BRE
Гость
« Ответ #12 : Декабрь 15, 2008, 08:58 »

Код
C++ (Qt)
// Сигнал что ветка выбрана мышкой
connect(knowtree,SIGNAL(pressed(const QModelIndex &)),
        this,SLOT(on_knowtree_clicked(const QModelIndex &)));
 
// Сигнал что ветка выбрана стрелками на клавиатуре
connect(knowtree->selectionModel(), SIGNAL(currentRowChanged (const QModelIndex&, const QModelIndex&)),
        this, SLOT(on_knowtree_clicked(const QModelIndex&)));
 
А зачем ты обрабатываешь pressed()? При выборе ветки мышкой currentRowChanged() должен и так вызываться...
Записан
SABROG
Гость
« Ответ #13 : Декабрь 15, 2008, 09:34 »

Попробуй флаг Qt::QueuedConnection передавать в метод connect. Тогда слоты будут вызываться при возвращении в основной eventLoop.
Записан
Tonal
Гость
« Ответ #14 : Декабрь 15, 2008, 11:23 »

2 SABROG У автора немного другая проблема - во время долгого вычисления можно произвести действие в итерфейсе (выбрать другую ветку дерева) из за которого вычисление может порушиться.

В этом случае либо дизаблить/замараживать интерфейс, либо максимально отвязываться от UI - т.е. пришло событие, собираем всю нужную инфу в отдельную структуру и дальше работаем именно с ней а не с виджетами.
Записан
Страниц: [1] 2 3   Вверх
  Печать  
 
Перейти в:  


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