[QTcpSocket] Cannot create children for a parent that is in a different thread
Hello, I am trying to deal with threading affinity. I think I did everything like it was suggested in the "you're doing it wrong" article, but still I receive error messages from the socket when I call waitForConnected method:
"QObject: Cannot create children for a parent that is in a different thread.
(Parent is QTcpSocket(0x2022608), parent's thread is QThread(0x1fc8320), current thread is QThread(0x40fde8)"
Here is my code, I create controller class that is executed in the separate thread.
Code:
test
::test(QWidget *parent, Qt
::WFlags flags
){
ui.setupUi(this);
controller = new Controller();
controller->moveToThread(&thread);
connect(&thread, SIGNAL(started()), controller, SLOT(start()));
connect(controller, SIGNAL(finished()), &thread, SLOT(quit()));
connect(this,
SIGNAL(fileAdded
(const QString &)), controller,
SLOT(enqueueFile
(const QString &)));
emit fileAdded("lalalala");
thread.start();
}
Controller class declaration:
Code:
#ifndef CONTROLLER_H
#define CONTROLLER_H
#include <QThread>
#include <QTcpSocket>
{
Q_OBJECT
public:
~Controller();
public slots:
void enqueueFile
(const QString &fileName
);
void start();
signals:
void finished();
private:
};
#endif // CONTROLLER_H
Controller class implementation:
Code:
#include "controller.h"
#include <QDebug>
#include <QTimer>
#include <QEventLoop>
Controller
::Controller(QObject *parent
) {
}
Controller::~Controller()
{
}
void Controller::start()
{
socket.connectToHost("some-host", 777);
socket.waitForConnected(); // here goes the error
socket.disconnectFromHost();
socket.waitForDisconnected(); // here goes the error again
}
void Controller
::enqueueFile(const QString &fileName
) {
qDebug() << fileName;
}
I know threads are not really needed for sockets, I could use signal/slot mechanism, but this is just for test. Please help me to understand what is wrong.
Re: [QTcpSocket] Cannot create children for a parent that is in a different thread
Did you ever find a solution? I'm in a similar spot. I have a class that polls a serial port for data. Upon receiving data, it passes it to another class to analyze the data. The Analyze class emits a signal if the data requires logging. A third class, Logger, has a slot for the data to log it to a web server. I separated the Logger class so I could possibly use it elsewhere within the program.
Currently, I'm loading the Polling class in main and shuffling it off to the globalInstace of QThreadPool. I load up the other two classes within the Polling class and connect the SIGNAL/SLOT there.
Re: [QTcpSocket] Cannot create children for a parent that is in a different thread
I think the problem in the OP is that socket is not a child of Controller, and so it has been 'left behind' in the old thread.
I think this would solve the problem
Code:
Controller
::Controller(QObject *parent
) : socket(this)
{
}
If your compiler supports it, otherwise
Code:
Controller
::Controller(QObject *parent
){
socket.setParent(this);
}
should be ok as well.
Re: [QTcpSocket] Cannot create children for a parent that is in a different thread
Thanks amieto!
What's happening now for me, is the SIGNAL from Analyzer appears to be emitted, but the SLOT in Logger never gets run.
Code:
#include <QtCore/QCoreApplication>
#include <QThread>
#include "logger.h"
#include "pollcontroller.h"
#include "analyzer.h"
int main(int argc, char *argv[])
{
int port = 85;
PollController *pollController = new PollController();
pollController->setup(1,1000);
Analyzer *analyzer = pollController->getAnalyzer();
pollController->moveToThread(&pollThread);
Logger *logger = new Logger();
logger->setup(host,port,analyzer);
logger->moveToThread(&loggerThread);
return a.exec();
}
Code:
#ifndef POLLCONTROLLER_H
#define POLLCONTROLLER_H
#include <QObject>
#include <QThread>
#include "analyzer.h"
#include "sleep.h"
class PollController
: public QObject{
Q_OBJECT
public:
explicit PollController
(QObject *parent
= 0);
void setup(int,int);
Analyzer*& getAnalyzer();
signals:
public slots:
private:
void loopNumbers(int,int);
Analyzer *analyzer;
};
#endif // POLLCONTROLLER_H
Code:
#include "pollcontroller.h"
PollController
::PollController(QObject *parent
) :{
}
void PollController::setup(int begin, int end) {
analyzer = new Analyzer(this);
loopNumbers(begin,end);
}
void PollController::loopNumbers(int begin, int end) {
Sleep sleep;
QString skipMsg
= "99.00.121.01.03939021";
// Generate some data to check
for (int x=begin; x<end; x++) {
qDebug() << "poll received:" << x;
if (x % 4 == 0) {
analyzer->analyze(logMsg);
} else if (x % 2 == 0) {
analyzer->analyze(skipMsg);
}
sleep.msleep(1000);
}
}
Analyzer*& PollController::getAnalyzer() {
return analyzer;
}
Code:
#ifndef ANALYZER_H
#define ANALYZER_H
#include <QObject>
#include <QDebug>
{
Q_OBJECT
public:
explicit Analyzer
(QObject *parent
= 0);
void analyze(QString&);
signals:
void msgToLog(QString&);
public slots:
};
#endif // ANALYZER_H
Code:
#include "analyzer.h"
#include <QStringList>
Analyzer
::Analyzer(QObject *parent
) :{
}
void Analyzer
::analyze(QString &msg
) {
if (msg.contains(".")) {
if (fields.at(2) == "050") {
emit(msgToLog(msg));
qDebug() << "emit(msgToLog(msg))";
return;
}
qDebug() << "msg" << msg << "didn't contain 050 command";
}
}
Code:
#ifndef LOGGER_H
#define LOGGER_H
#include <QObject>
#include <QTcpSocket>
#include <QAbstractSocket>
#include <QDebug>
#include "analyzer.h"
{
Q_OBJECT
public:
explicit Logger
(QObject *parent
= 0);
void setup(QString&,int&,Analyzer*&);
signals:
public slots:
void connected();
void disconnected();
void bytesWritten(qint64);
void readyRead();
private:
int port;
};
#endif // LOGGER_H
Code:
#include "logger.h"
{
}
void Logger
::setup(QString &host,
int &port, Analyzer
*&analyzer
) {
connect(analyzer,SIGNAL(msgToLog(QString&)),this,SLOT(write(QString&)),Qt::AutoConnection);
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 Logger::connected()
{
qDebug() << "Connected";
}
void Logger::disconnected()
{
qDebug() << "Disconnected";
}
void Logger::bytesWritten(qint64)
{
}
void Logger::readyRead()
{
qDebug() << "socket readAll:" << socket->readAll();
}
{
qDebug() << "write msg:" << msg;
socket->connectToHost(host,port);
if (!socket->waitForConnected(500)) {
qDebug() << "Error:" << socket->errorString();
return;
}
serverMsg.append("GET /log/test/msg/");
serverMsg.append(msg);
serverMsg.append("/time/1234567859 HTTP/1.0\r\n\r\n");
socket->write(serverMsg);
}
Code:
#ifndef SLEEP_H
#define SLEEP_H
#include <QWaitCondition>
#include <QMutex>
class Sleep
{
public:
Sleep();
void msleep(unsigned long msecs);
};
#endif // SLEEP_H
Code:
#include "sleep.h"
Sleep::Sleep()
{
}
void Sleep::msleep(unsigned long msecs) {
mutex.lock();
waitCondition.wait(&mutex,msecs);
mutex.unlock();
}
Re: [QTcpSocket] Cannot create children for a parent that is in a different thread
Ok. So I took a different approach. I decided to just fire up a new instance of my Logger class whenever the polling object that is running on its own thread has something to log to the web server. It seems to work in testing, I'm just wondering if I'm doing things correctly, or just getting lucky.
Re: [QTcpSocket] Cannot create children for a parent that is in a different thread
eewww, why are you pasing QString by reference for logging calls? Not even const reference! QString should definitely be passed by value.
If you slot doesn't get hit, first thing you should do is debug the connections - does qt give any error message? Then debug what happens after the signal.
Re: [QTcpSocket] Cannot create children for a parent that is in a different thread
Well, I think I found the issue. Passing QString by reference may be something that wasn't intended, but technically it works (slot will be invoked). I think, the problem is you emit signals before establishing connection.
Code:
PollController *pollController = new PollController();
// you emit signals here !
pollController->setup(1,1000);
Analyzer *analyzer = pollController->getAnalyzer();
pollController->moveToThread(&pollThread);
Logger *logger = new Logger();
// you establish connection here! doesn't even get called
logger->setup(host,port,analyzer);
However, it seems to not have any relation to my post. G00d luck.