Пишу небольшой сервер, где при нажатии кнопки создаётся новый поток (th) и там запускается TCP слушатель определённого порта. При каждом новом TCP подключении необходимо делать два новых коннекта объектов, оба которых созданы и работают в потоке (th).
std::thread th([this]() -> void {
while (true) {
std::unique_ptr<Bs> bs = std::make_unique<Bs>();
bs->GetTcpServer()->listen(QHostAddress::Any, 9005);
connect(bs->GetTcpServer(), SIGNAL(newConnection()), bs.get(), SLOT(ConnectionWasEstablished()), Qt::QueuedConnection);
connect(bs.get(), SIGNAL(update_server_logs(QString)), this, SLOT(UpdateServerLog(QString)), Qt::QueuedConnection);
while (!bs->IsConnected()) { // Ждём следующего подключения.
std::this_thread::sleep_for(100ms);
}
bs_list_.push_back(std::move(bs));
}
});
Проблема в том, что при подключении TCP клиента до соответствующих слотов сигнал не доходит. Всё что я смог нагуглить - это то что скорее всего в новом потоке требуется свой «Event loop», чтобы мочь обрабатывать сигналы, но как его создать в новом потоке не понял.
Всё заработало когда я создал поток по статье которую нашёл Bearded Beaver. Добиться работоспособности с std::thread я так и не смог(. Большое спасибо всем кто помог, особенно Bearded Beaver и ixSci.
Добавьте в цикл QCoreApplication::processEvents();
, должно помочь.
Вообще говоря, Ваш код ужасен. Используете Qt? Используйте его возможности, его потоки и всё, что с ними связано. Вот статья про то, как правильно работать с QThread: Threads Events QObjects, там же есть русский перевод.
На случай если статья-источник потеряется, продублирую сюда решение из нее с некоторыми своими ремарками:
Не создавайте подклассов QThread!
Используйте moveToThread()
и "рабочий" класс-наследник от QObject
.
Далее описано, как Вы должны реализовать многопоточную операцию, используя класс QThread
.
Создайте класс-работник, который унаследован от класса QObject
.
Этот класс должен определять следующие сигналы и слоты:
Класс-работник:
class Worker : public QObject {
Q_OBJECT
public:
explicit Worker(QObject * parent = nullptr);
public slots:
void process();
signals:
void finished();
void error(QString err);
};
Использование в отдельном потоке:
// Создание потока
QThread* thread = new QThread;
Worker* worker = new Worker();
// Перемещаем класс-работник в отдельный поток
worker->moveToThread(thread);
// Связываем сигнал об ошибки со слотом обработки ошибок
connect(worker, SIGNAL(error(QString)), this, SLOT(errorHandler(QString)));
// Соединяем сигнал started потока, со слотом process класса-работника, чтобы выполнение началось сразу после запуска потока
connect(thread, SIGNAL(started()), worker, SLOT(process()));
// Обеспечиваем завершение работы потока и автоматическое очищение памяти объектов потока и работника при завершении работы
connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
// Запускаем цикл обработки событий для потока, теперь объект готов реагировать на сигналы
thread->start();
От себя добавлю, что такие воркеры отлично справляются с ролью потоков-демонов типа "висеть в памяти и при поступлении сигнала как-то на него реагировать", для этого запуск задачи цепляем не к сигналу started
потока, а к тому сигналу, на который надо реагировать и не испускаем сигнал finished
при завершении слота с задачей, тогда объект продолжит ждать поступления новых сигналов.
З.Ы. Пример кода старый, коннекты написаны в Qt4-style, лучше переделать на "новый" синтаксис.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Есть основной виджет, который скомпонован с помощью layout-ов и я хочу, чтобы во время выполнения соновной программы при определенных обстоятельствах...
Окружение: macOS, драйвер для оцифровки аналогового видео (кроме видео обрабатывается звук и VBI данные)
Имеется сгенерированный на ubuntu сертификат(servercrt) и ключ(server
Нужно создать папку в /home/user в Linux, для этого нужно в коде прописать путьКак получить имя этого user-а?