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

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

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

Сообщений: 2130



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

Old, этот коннект, вроде, между нитками получается. Вроде ж нельзя так соединять.
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



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

Old, этот коннект, вроде, между нитками получается. Вроде ж нельзя так соединять.
Почему нельзя? Улыбающийся
Если нам нужно, что бы метод вызвался сразу в момент посылки сигнала.

А так, он ставиться в очередь сообщений, которая не обрабатывается при ожидании в QThread::wait, и мы получаем цейтнот. Улыбающийся
Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 584


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

Рабочий пример.

Коннекты нужно перенести в конструктор, чтобы не происходили по нескольку раз. А то поток не может завершиться по одному нажатию Finish.
В деструкторе quit, wait - об этом уже писали.
Записан
xintrea
Супер активный житель
*****
Offline Offline

Сообщений: 754



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

Коннекты и перемещение в нить нужно в конструктор вынести

В конструтор чего? В конструктор MoveDetector или MainWindow?

Чем плохи коннекторы и перемещение, вызываемые при нажатии кнопки?
Записан

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

Сообщений: 2130



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

Почему нельзя? Улыбающийся
Видать, отложилось в подкорке
Цитировать
The connection type can be specified by passing an additional argument to connect(). Be aware that using direct connections when the sender and receiver live in different threads is unsafe if an event loop is running in the receiver's thread, for the same reason that calling any function on an object living in another thread is unsafe.
Только не соображу, как в данном случае работают eventloop и как обрабатывается соединение.

xintrea, у тебя просто по второму клику на кнопку старт повторно происходят коннекты и движение в нитку, где-то тут кроется проблема Улыбающийся
Записан
xintrea
Супер активный житель
*****
Offline Offline

Сообщений: 754



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

Рабочий пример.

Ага, вижу. Вы сделали так, что объект размещается в треде один раз, а потом просто перезапускается.

А я думал, что при остановке треда происходит завершение треда...

Вот сейчас смотрю, и вижу, что метода, обратного moveToThread просто нет. То есть, по сути, если объект класса QThread у нас на стеке, то проинитить мы его можем один только раз... Хотя нет, мы же можем засунуть в этот тред другой объект... А почему тот же самый не можем заново засунуть?
Записан

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

Сообщений: 4350



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

Только не соображу, как в данном случае работают eventloop и как обрабатывается соединение.
Ну давайте смотреть:
В конструкторе окна создаются два объекта классов QThread и MoveDetector. Оба этих объекта пока принадлежат главной нитке (она же GUI-нить), в которой они создавались.
Дальше происходит перемещении объекта moveDetector в контекст другой нити. Заметьте, что объект класса QThread, так и остался в главной нитке.
Теперь при отсылке сигналом из объекта moveDetector объекту нитки moveDetectorThread будет использован метод QueuedConnection, т.е. вместо прямого вызова слота, будет добавляться сообщение в очередь сообщений главной нити.
Вся цепочка выглядит так:
Мы в главной нитке вызываем doExit и вызываем wait, которая блокирует главную нить в ожидании завершения процесса (ее очередь сообщений при этом блокируется).
Теперь при переключении на рабочую нить, происходит отсылка сигнала finished, который добавляет сообщение в очередь главной нитки с вызовом метода QThread::quit. Но обработка сообщений в главной нитке - заблокировано, мы там ждем завершение нитки в wait.
Все, мы в цейтноте. В очереди главной нитки лежит сообщение для завершения рабочей нитке, но мы их не обрабатываем, потому что ждем ее завершение. Улыбающийся
Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #22 : Декабрь 01, 2017, 09:18 »

Как происходит блокировка, я понял.
Мне не совсем понятна цитата, приведённая в #19. Я её скопировал из документации к 4 qt. В qt5 уже такого не нашёл.
Цитировать
if an event loop is running in the receiver's thread
Что это значит? Что нельзя дёргать слот вне главной нитке или то что нельзя напрямую коннектить, т.к. в нитке имеется свой eventloop? Или вообще всё это не имеет значения относительно qt5?
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #23 : Декабрь 01, 2017, 09:47 »

Что это значит? Что нельзя дёргать слот вне главной нитке или то что нельзя напрямую коннектить, т.к. в нитке имеется свой eventloop? Или вообще всё это не имеет значения относительно qt5?
Это зависит от слота. Улыбающийся
QThread::exit под защитой мьютекса останавливает все запущенные в этой нитке eventloop. Этот слот безопасно можно вызывать из любой нитки.
А можно написать такой метод, который будет опасно вызывать из другой нитки. Например, если он будет не реентерабельным.

Простой пример, метод кеширует некоторые данные во время своего выполнения:
Код
C++ (Qt)
void Worker::run()
{
   m_cacheData = 0;    // Вначале сбросили кеш.
   while( !isEnd() )
   {
       // Долгие вычисления
       // m_cacheData читается и модифицируется
   }
}
 

Если мы запустим этот метод в контексте рабочей нитки, он начнет выполняться, прервется планировщиком в середине работы и управление получит другой поток, который напрямую вызовет этот метод (DirectConnection это прямой вызов), то кеши обновятся и когда управление вернется рабочей нитке, в кешах будет каша. Такие методы можно вызывать только через очередь.
Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #24 : Декабрь 01, 2017, 11:30 »

QThread::exit под защитой мьютекса
Об этом можно было как-то узнать, не залезая в исходники?
Спасибо. Кажется, я всё понял.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #25 : Декабрь 02, 2017, 09:41 »

Добавьте в on_buttonStart_clicked строку
Код
C++ (Qt)
moveDetectorThread.moveToThread(&moveDetectorThread);
 
Т.е. не только moveDetector, но и moveDetectorThread должны принимать ивенты в рабочей нитке. Иначе quit засылается в луп главной нитки, а она занята печатью. Ну и практичнее использовать moveDetectorThread.wait вместо цикла while 
Записан
zhbr
Гость
« Ответ #26 : Декабрь 02, 2017, 10:00 »

Добавьте в on_buttonStart_clicked строку
Код
C++ (Qt)
moveDetectorThread.moveToThread(&moveDetectorThread);
 
Т.е. не только moveDetector, но и moveDetectorThread должны принимать ивенты в рабочей нитке. Иначе quit засылается в луп главной нитки, а она занята печатью. Ну и практичнее использовать moveDetectorThread.wait вместо цикла while 
Не надо moveDetectorThread помещать в тот же поток. "QThread objects are not threads; they're control objects around a thread, therefore meant to be used from another thread (usually, the one they're living in)" (c) https://wiki.qt.io/Threads_Events_QObjects
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #27 : Декабрь 02, 2017, 11:30 »

Не надо moveDetectorThread помещать в тот же поток. "QThread objects are not threads; they're control objects around a thread, therefore meant to be used from another thread (usually, the one they're living in)" (c) https://wiki.qt.io/Threads_Events_QObjects
Ага, это жевалось не раз. moveToThread(this) - это плохо! А почему? Да просто "так пишут", ну наверное правда Улыбающийся Заметим что технически это совершенно корректно, речь идет только о том что это может быть не лучшим архитектурным решением.

Проблема (мелкая) в том что если moveDetector::finished испускается из рабочей нитки, то главная (в которой принимает события moveDetectorThread) не может принять его немедленно после установки флага, нужно выйти в событийный цикл. Это можно решать по-всякому. Возможно лучше всего убрать moveDetector::finished, т.е. просто "выйти вон" по exitFlag, а quit/exit сделать из главной нитки как в варианте ssoft. Если проблема ясна, то решения найдутся
Записан
Страниц: 1 [2]   Вверх
  Печать  
 
Перейти в:  


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