Another "Cannot create children for a parent that is in a different thread"
-
I think I have a little bit different of a scenario that I can't seem to wrap my head around regarding SIGNAL/SLOT and QThreadPool. See code below:
@#include <QtCore/QCoreApplication>
#include <QObject>
#include <QDebug>
#include <QThreadPool>
#include "analyzer.h"
#include "logger.h"
#include "poller.h"int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);Analyzer *analyzer = new Analyzer(); Logger *logger = new Logger(); logger->setup(); Poller *poller = new Poller(logger,analyzer); QThreadPool::globalInstance()->start(poller); //return a.exec();
}@
Pretty simple. I have a class that analyzes the info from my poller object and another class handles the logging. I needed to separate them out because I wanted other classes/threads to be able to use the Logger class. The Analyzer class emits the SIGNAL when the condition is met, and the Logger class should process the data and send it to my web server. The Poller class connects to a serial device and is polling it for data to analyze.
@#include <QRunnable>
#include <QObject>
#include <QDebug>
#include "analyzer.h"
#include "logger.h"
#include "mysleep.h"class Poller : public QObject, public QRunnable
{
Q_OBJECT
public:
Poller(Logger *&logger,Analyzer *&analyzer);protected:
void run();public slots:
void pollerSlot();private:
Analyzer *analyzer;
};#endif // POLLER_H
@@#include "poller.h"
Poller::Poller(Logger *&logger,Analyzer *&analyzer)
{
this->analyzer = analyzer;
connect(analyzer,SIGNAL(sendMsg(QString&)),logger,SLOT(printMsg(QString&)),Qt::DirectConnection);
}void Poller::pollerSlot()
{
}void Poller::run() {
// Simulate grabbing some data
quint64 num = 0;
while(num < 99999999) {
qDebug() << num;if (num % 2 == 0) analyzer->checkNum(num); MySleep::mymsleep(250); num++; }
}@
I thought since the run function is in "poller", I should connect the signals/slots there.
@#ifndef LOGGER_H
#define LOGGER_H#include <QObject>
#include <QDebug>
#include <QTcpSocket>
#include <QAbstractSocket>class Logger : public QObject
{
Q_OBJECT
public:
explicit Logger(QObject *parent = 0);
void setup();signals:
public slots:
void printMsg(QString&);
void connected();
void disconnected();
void bytesWritten (qint64 bytes);
void readyRead();private:
QTcpSocket *socket;
};#endif // LOGGER_H@
@#include "logger.h"
Logger::Logger(QObject *parent) :
QObject(parent)
{}
void Logger::setup() {
}
void Logger::printMsg(QString &msg) {
qDebug() << "Logger msg:" << msg;socket = new QTcpSocket(this); connect(socket,SIGNAL(connected()), this, SLOT(connected())); connect(socket,SIGNAL(disconnected()), this, SLOT(disconnected())); connect(socket,SIGNAL(readyRead()), this, SLOT(readyRead())); connect(socket,SIGNAL(bytesWritten(qint64)),this,SLOT(bytesWritten(qint64))); socket->connectToHost("vm1",80); if(!socket->waitForConnected(5000)) { qDebug() << "Error: " << socket->errorString(); } qDebug() << "Connecting...";
}
void Logger::connected()
{
qDebug() << "Connected!";socket->write("HEAD / HTTP/1.0\r\n\r\n");
}
void Logger::disconnected()
{
qDebug() << "Disconnected!";
}void Logger::bytesWritten (qint64 bytes)
{
qDebug() << "we wrote: " << bytes;
}void Logger::readyRead()
{
qDebug() << "Reading...";
qDebug() << socket->readAll();
}@I should note that I originally had the socket creation - signal/slot connections in the "setup" function and called it from main, but moved it to the slot due to "Cannot connect (null)::destroyed() to QHostInfoLookupManager::waitForThreadPoolDone()" error.
@#ifndef ANALYZER_H
#define ANALYZER_H#include <QObject>
#include <QDebug>class Analyzer : public QObject
{
Q_OBJECT
public:
explicit Analyzer(QObject *parent = 0);
void checkNum(quint64 num);signals:
QString sendMsg(QString&);public slots:
};
#endif // ANALYZER_H@
-
Which line are you getting that error on?
-
The error listed above (Cannot connect) happens when the SLOT is run. My main issue though is the "Cannot create children for a parent that is in a different thread." which happens when I get to "socket->connectToHost"
-
So I decided to take a slightly different approach. Following the advice of the Qt masters, I decided to do QThread(ing) the correct way:
@
PollController *pollController = new PollController();
pollController->setup(1,1000);QThread pollThread; pollController->moveToThread(&pollThread); Analyzer *analyzer = pollController->getAnalyzer(); Logger *logger = new Logger(); logger->setup(host,port,analyzer); QThread loggerThread; logger->moveToThread(&loggerThread);
@
In this version, I'm starting my polling class and "moveToThread" as suggested. In the polling class, I'm still creating the Analyzer class instance, but now I'm pulling back a reference to it and passing that to my Logger class when I set that one up. There I'm making the connection for SIGNAL/SLOT:
@
void Logger::setup(QString &host, int &port, Analyzer *&analyzer)
{
connect(analyzer,SIGNAL(msgToLog(QString&)),this,SLOT(write(QString&)));socket = new QTcpSocket(this->parent()); connect(socket,SIGNAL(connected()),this,SLOT(connected())); connect(socket,SIGNAL(disconnected()),this,SLOT(disconnected())); connect(socket,SIGNAL(readyRead()),this,SLOT(readyRead())); connect(socket,SIGNAL(bytesWritten(qint64)),this,SLOT(bytesWritten(qint64))); this->host = host; this->port = port;
}
@@
void Analyzer::analyze(QString &msg)
{
if (msg.contains(".")) {
QStringList fields = msg.split(".");if (fields.at(2) == "050") { emit(msgToLog(msg)); qDebug() << "emit(msgToLog(msg))"; return; } qDebug() << "msg" << msg << "didn't contain 050 command"; }
}
@I've tried setting the connection type to Qt::DirectConnection with no difference. I'm also assigning the parent of my Logger class as the parent to the QTcpSocket here which I think gets rid of the original "Cannot create children..." error.
My problem now is that the SLOT in the Logger never runs, even though I see the code block in my Analyzer class get executed.
Am I not connecting things correctly?
-
Moving on. I decided to take a different tact, and maybe now I'm doing it the right way.
@
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);PollController *pollController = new PollController(); pollController->setup(1,1000); QThread *pollThread = new QThread(); QObject::connect(pollThread,SIGNAL(started()),pollController,SLOT(startPolling())); pollController->moveToThread(pollThread); pollThread->start(); return a.exec();
}
@Inside the "pollController" class, I create a new instance of my QTcpSocket logger class when I have data to report to the web server.
@
void PollController::msgReceived(QString &msg)
{
QString host = "web-dev";
int port = 85;
//QString msg = "99.00.050.00.12345678.*";qDebug() << "pollController received signal from analyze:" << msg; //emit(msgToLog(msg)); // Fire up a new logger Logger *logger = new Logger(this); logger->setup(host,port,msg);
}
@It seems to work, I just wonder if I'm really doing things correctly now or am I just getting lucky that it's working in testing?