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

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

Страниц: 1 [2]   Вниз
  Печать  
Автор Тема: [Решено] Thread tried to wait on itself  (Прочитано 11288 раз)
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #15 : Март 15, 2021, 16:13 »

корректен?

Нет, потому что тред незаджойнен, а незаджойненые треды ведут к крашам (когда main() уже вышел, Глобал статики развалились, а тред еще жужжит)
Записан
sergek
Гипер активный житель
*****
Offline Offline

Сообщений: 872


Мы должны приносить пользу людям.


Просмотр профиля
« Ответ #16 : Март 15, 2021, 20:10 »

Все понял, признаю свои ошибки, больше не буду))
Записан

Qt 5.13.0 Qt Creator 5.0.1
Win10, Ubuntu 20.04
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #17 : Март 16, 2021, 11:54 »

Нет, потому что тред незаджойнен, а незаджойненые треды ведут к крашам (когда main() уже вышел, Глобал статики развалились, а тред еще жужжит)
Вот есть желание сделать какого-то worker'а, который по собственной инициативе (может быть) запускает workerThrеad (возможно член класса), ну и завершает/удаляет ее в деструкторе. Что тут плохого/некорректного ?

Правда возникает проблемка как дождаться завершения workerThrеad не имея к ней доступа в main нитке
Записан
sergek
Гипер активный житель
*****
Offline Offline

Сообщений: 872


Мы должны приносить пользу людям.


Просмотр профиля
« Ответ #18 : Март 16, 2021, 21:38 »

Правда возникает проблемка как дождаться завершения workerThrеad не имея к ней доступа в main нитке
Такой вокер имеет место на существование с единственным ограничением - его удаление должно выполняться в другом потоке, т.е. не в том, где создавался Worker и workerThread. Тогда текущий поток и поток workerThread не совпадают и wait() работает.
У меня это невозможно, к сожалению.
Записан

Qt 5.13.0 Qt Creator 5.0.1
Win10, Ubuntu 20.04
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #19 : Март 17, 2021, 11:17 »

Такой вокер имеет место на существование с единственным ограничением - его удаление должно выполняться в другом потоке, т.е. не в том, где создавался Worker и workerThread. Тогда текущий поток и поток workerThread не совпадают и wait() работает.
У меня это невозможно, к сожалению.
А как удалить worker'а из main если worker->thread() == workerThread ? Если ничего не путаю, получим ошибку выполнения (и это правильно)

Проблемка не выглядит ужасной, можно напр взводить футуру по сигналу finished (workerThread), а в main ждать на этой футуре. С др стороны затея "worker сам разбирается со своими нитками" имеет смысл
Записан
sergek
Гипер активный житель
*****
Offline Offline

Сообщений: 872


Мы должны приносить пользу людям.


Просмотр профиля
« Ответ #20 : Март 17, 2021, 14:45 »

А как удалить worker'а из main если worker->thread() == workerThread ?
Да никак. Controller и Worker в моем примере создаются и удаляются в main, из-за чего и проблема.
Но можно добавить еще один вспомогательный поток, который должен служить только для одного - при завершении программы удалить все worker'ы. Тогда описанный подход должен сработать.
Нет времени проверять))

PS. Кстати, у себя в проекте я сделал по классической схеме (менеджер потока создается в Controller), но сколько гимора из-за этого поимел (отчасти из-за небрежной иерархии принадлежности объектов), что лучше бы проверил и сделал такой вспомогательный поток))
« Последнее редактирование: Март 17, 2021, 14:51 от sergek » Записан

Qt 5.13.0 Qt Creator 5.0.1
Win10, Ubuntu 20.04
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #21 : Март 18, 2021, 08:37 »

Но можно добавить еще один вспомогательный поток, который должен служить только для одного - при завершении программы удалить все worker'ы. Тогда описанный подход должен сработать.
Зачем же нитками так разбрасываться? Можно напр ждать на футуре или семафоре, может оформить выход из главного цикла в 2 этапа, первый удаление workке'ов
Записан
sergek
Гипер активный житель
*****
Offline Offline

Сообщений: 872


Мы должны приносить пользу людям.


Просмотр профиля
« Ответ #22 : Март 19, 2021, 18:41 »

Чтобы тема приобрела какой-то завершенный вид, я доработал пример, добавив в него вспомогательный класс WorkerPool и поток poolThread для него. Класс служит для хранения указателей на worker'ы в виде простого списка и их удаления в своем потоке (чтобы wait сработал, как надо). Здесь создаются 2 worker'а:
Код
C++ (Qt)
Controller::Controller(QObject *parent) : QObject(parent)
{
   WorkerPool* pool = new WorkerPool;
   connect(&poolThread, &QThread::finished, pool, &QObject::deleteLater);
   pool->moveToThread(&poolThread);
   poolThread.start();
 
   for(int i=0; i<2; i++) {
       Worker *worker = new Worker(i);
       pool->append(worker);
 
       connect(this, &Controller::operate, worker, &Worker::doWork);
       connect(worker, &Worker::resultReady, this, &Controller::handleResults);
   }
 
 
   connect(&timer, &QTimer::timeout, [this]() { emit operate("do it"); });
}

Удаление pool выполняется по сигналу завершения вспомогательного потока finished, поток завершается в деструкторе контроллера:
Код
C++ (Qt)
Controller::~Controller() {
   poolThread.quit();
   poolThread.wait();
}

В деструкторе пула удаляются worker'ы оператором delete (это необходимо, чтобы вызвать деструктор worker'а в потоке пула):
Код
C++ (Qt)
WorkerPool::~WorkerPool() {
   for(auto worker: pool) {
       delete worker;
   }
}

Вот такой вывод этого примера (в начале каждого сообщения - идентификатор потока:
Код:
0x33E8 pool created
0x33E8 worker 1 created
0x33E8 worker 2 created
start work
0x0ef4 do it 1: done
0x3e78 do it 2: done
0x0ef4 do it 1: done
0x3e78 do it 2: done
0x0ef4 do it 1: done
0x3e78 do it 2: done
end work
0x3BBC worker 1 deleted
0x3BBC worker 2 deleted
0x3BBC pool deleted

Напомню, что идея не моя)) Если интересно, то первоисточник тут: https://github.com/StefanFrings/QtWebApp/blob/master/QtWebApp/httpserver/httpconnectionhandler.cpp
Там не все очевидно, автор мне подсказал, что удаление выполняется в HttpConnectionHandlerPool::cleanup().
Записан

Qt 5.13.0 Qt Creator 5.0.1
Win10, Ubuntu 20.04
Страниц: 1 [2]   Вверх
  Печать  
 
Перейти в:  


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