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

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

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Сегфолт при завершении работы потока QThread - что не так?  (Прочитано 14849 раз)
xintrea
Супер активный житель
*****
Offline Offline

Сообщений: 754



Просмотр профиля WWW
« : Ноябрь 30, 2017, 13:05 »

Есть класс окна, в полях которого имеются два свойства:

Код:
 
protected:
    QThread moveDetectorThread;
    MoveDetector moveDetector; // Некий объект для запуска в потоке

В конструкторе есть следующий код, и он нормально запускает объект в потоке:

Код:
    // Запуск цикла объекта при старте потока
    connect(&moveDetectorThread, &QThread::started, &moveDetector, &MoveDetector::run);
    
    // Соединения для корректного завершения потока
    connect(&moveDetector, SIGNAL(finished()), &moveDetectorThread, SLOT(quit()));
    connect(&moveDetector, SIGNAL(finished()), &moveDetector, SLOT(deleteLater()));
    connect(&moveDetectorThread, SIGNAL(finished()), &moveDetectorThread, SLOT(deleteLater()));
    
    moveDetector.moveToThread(&moveDetectorThread); //  Объект переносится в тред
    moveDetectorThread.start(); // Тред запускается

Сам объект имеет метод основного цикла и метод, устанавливающий флаг выхода:

Код:
void MoveDetector::run()
{
    exitFlag=false;

    for(;;){
        update();
        if(exitFlag) {
            emit finished();
            return;
         }
    }
}


void MoveDetector::doExit()
{
    exitFlag=true;
}

В деструкторе окна я написал такой код:

Код:
    moveDetector.doExit();
    while(!moveDetectorThread.isFinished()) {
        qDebug() << "Wait finished move detector...";
    }

В результате, при срабатывании деструктора программа крешится вот так:

Код:
Wait finished move detector...
                 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
Wait finished move detector...
Wait finished move detector...
Wait finished move detector...
The program has unexpectedly finished.
Процесс был завершён принудительно.
/home/xi/work/develop/cpp/MoveNoid/build-MoveNoid-Desktop_Qt_5_9_2_GCC_64bit-Debug/MoveNoid crashed.

Информацию брал вот отсюда: https://habrahabr.ru/post/150274/

Вопрос: почему крешится программа? Что сделать чтоб поток нормально завершался?

UPD: Сделал минимальный пример: http://rgho.st/8dD7n4ljc
При нажатии Stop все зависает, окно перестает отвечать.
« Последнее редактирование: Ноябрь 30, 2017, 14:21 от xintrea » Записан

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

Сообщений: 4350



Просмотр профиля
« Ответ #1 : Ноябрь 30, 2017, 13:43 »

Вот это уберите:

Код
C++ (Qt)
   connect(&moveDetector, SIGNAL(finished()), &moveDetector, SLOT(deleteLater()));
   connect(&moveDetectorThread, SIGNAL(finished()), &moveDetectorThread, SLOT(deleteLater()));
 

Эти объекты удалятся автоматически.
Записан
xintrea
Супер активный житель
*****
Offline Offline

Сообщений: 754



Просмотр профиля WWW
« Ответ #2 : Ноябрь 30, 2017, 13:56 »

Убрал, проблема осталась.
Записан

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

Сообщений: 4350



Просмотр профиля
« Ответ #3 : Ноябрь 30, 2017, 14:06 »

Убрал, проблема осталась.
Давайте попробуем так: Улыбающийся
Код
C++ (Qt)
   moveDetector.doExit();
//    while(!moveDetectorThread.isFinished()) {
//        qDebug() << "Wait finished move detector...";
//   }
   moveDetectorThread.wait();
 
Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #4 : Ноябрь 30, 2017, 14:07 »

Очередность коннектов и moveToThread никак не влияет?
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #5 : Ноябрь 30, 2017, 14:08 »

Кстати, это тоже не нужно:
Код
C++ (Qt)
connect(&moveDetector, SIGNAL(finished()), &moveDetectorThread, SLOT(quit()));
 
Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #6 : Ноябрь 30, 2017, 14:18 »

Кто родитель у moveDetector?
Записан
xintrea
Супер активный житель
*****
Offline Offline

Сообщений: 754



Просмотр профиля WWW
« Ответ #7 : Ноябрь 30, 2017, 14:22 »

Кстати, это тоже не нужно:
Код
C++ (Qt)
connect(&moveDetector, SIGNAL(finished()), &moveDetectorThread, SLOT(quit()));
 

Добавил в топик готовый минимальный пример, чтоб обсуждение было более предметно.
Записан

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

Сообщений: 754



Просмотр профиля WWW
« Ответ #8 : Ноябрь 30, 2017, 14:23 »

Кто родитель у moveDetector?

QObject
Записан

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

Сообщений: 754



Просмотр профиля WWW
« Ответ #9 : Ноябрь 30, 2017, 14:34 »

Давайте попробуем так: Улыбающийся
Код
C++ (Qt)
   moveDetector.doExit();
//    while(!moveDetectorThread.isFinished()) {
//        qDebug() << "Wait finished move detector...";
//   }
   moveDetectorThread.wait();
 

Сделал:

Код:
    moveDetector.doExit();
    moveDetectorThread.wait();
    qDebug() << "Success finish.";

Проблема практически все та же - поток останавливается, но окно перестает отвечать. И сообщения о завершении нет.
Записан

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

Сообщений: 4350



Просмотр профиля
« Ответ #10 : Ноябрь 30, 2017, 14:38 »

Код
C++ (Qt)
   moveDetector.doExit();
   moveDetectorThread.quit();
   moveDetectorThread.wait();
 

doExit завершает выполнения метода run MoveDetector'а, а после этого запускается цикл обработки событий самой нитки (в QThread::run вызывается метод exec()).
Вот второй quit будет завершать его.
Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #11 : Ноябрь 30, 2017, 14:47 »

В примере имеется вызов слота quit.
Но до него не доходит очередь из-за цикла проверки завершения нити. processEvents доказывает это.
В таком исполнении выход происходит.
Код
C++ (Qt)
   while(!moveDetectorThread.isFinished()) {
       qApp->processEvents();
       qDebug() << "Wait finished move detector...";
   }
 
Код выше написал только для объяснения. К использованию не рекомендую.
Записан
xintrea
Супер активный житель
*****
Offline Offline

Сообщений: 754



Просмотр профиля WWW
« Ответ #12 : Ноябрь 30, 2017, 14:49 »

doExit завершает выполнения метода run MoveDetector'а, а после этого запускается цикл обработки событий самой нитки (в QThread::run вызывается метод exec()).
Вот второй quit будет завершать его.

Не понял. То есть, у меня из-за того, что MoveDetector::run() имеет бесконечный цикл, то обработки событий нитки вообще не происходило?

Ваше исправление:

moveDetector.doExit();
moveDetectorThread.quit();
moveDetectorThread.wait();

работает, но только один раз. Если снова запустить поток, то при нажатии Stop ничего происходить не будет, поток как работал, так и продолжит работать. Вот это мне непонятно.
Записан

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

Сообщений: 2130



Просмотр профиля
« Ответ #13 : Ноябрь 30, 2017, 14:52 »

работает, но только один раз.

Коннекты и перемещение в нить нужно в конструктор вынести
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #14 : Ноябрь 30, 2017, 15:02 »

обработки событий нитки вообще не происходило?
Да.

Еще один вариант, добавить такой коннект:
Код
C++ (Qt)
connect(&moveDetector, &MoveDetector::finished, &moveDetectorThread, &QThread::quit, Qt::DirectConnection);
 
что-бы слот QThread::quit выполнялся прямым вызовом, а не ставился в очередь.
Тогда руками quit вызывать не придется.
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


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