QObject::moveToThread() with child objects! [SOLVED]
-
Hi there.
OK. I read all the articles and i think i got QThreads right from the beginning on.
My problem has another much deeper root.I made up a sand box code:
@class BasicThread: public QThread
{
public:
BasicThread(QObject* parent=0): QObject(parent){ }
protected:
virtual void run() { exec(); }
};int main(int argc, char* argv[])
{
QApplication *a = new QApplication(argc, argv);BasicThread* thread = new BasicThread();
QTcpServer* socket = new QTcpServer();
socket->moveToThread(thread);
socket->listen(QHostAddress::Any, 1234);
thread->start();
return a->exec();
}
@Now QT streams the following error:
QObject: Cannot create children for a parent that is in a different thread!
(Parent is QTcpServer ...) ...OK. So far so bad.
QTcpServer::listen() seems to create a new object! Which would make sense!
If i remove the line: @socket->listen(QHostAddress::Any, 1234);@
the error wont appear!My solution for now is to catch the started() signal of the thread and call the line in the catching slot. But this makes things very complicated for me! I would have to give all new generated sockets to a worker (in a list) and the process() or work() method would call listen() of each socket in this list. That also means, that i need a worker for each different class which will be instanciated in my init method (see first post).
Any ideas to do that easier with QT?
-
[quote author="Seraph" date="1354789060"]
@
class BasicThread: public QThread
{
public:
BasicThread(QObject* parent=0): QObject(parent){ } // <------ why not QThread(parent) ?
protected:
virtual void run() { exec(); } // this is already QThreads default implementation
};
@
[/quote]Why are you deriving from QThread and then only use QObjects constructor for the constructor of your subclass?
Also you don't need to subclass QThread at all for your use case. This would be sufficient:
@
int main(int argc, char* argv[])
{
QApplication *a = new QApplication(argc, argv);QThread* thread = new QThread(a);
QTcpServer* socket = new QTcpServer();
socket->moveToThread(thread);
connect(thread, SIGNAL(finished()), socket, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));socket->listen(QHostAddress::Any, 1234);
thread->start();
return a->exec();
}
@ -
Hi KA510,
First of all, sorry! It is ofcourse a mistake: It should be QThread not QObject (Would not even compile i guess)
I derive the QThread class because of run() calling exec(). If i don't, the application will crash. This is when i do not use QThread(a)!
The problem is still there! KA510 did you test your code? Did you get the same result and error message?
Thanks for your effort
-
Sry I didn't test the code, that was just brain to terminal. Did you debug the test app? Where does it crash and what's the call stack like? It's just a guess but maybe this has to do with the fact that the main eventloop only starts after the a->exec() call.
I did something very similar in different applications and it always worked just fine. -
The crash is not my problem! The problem is still the fact that i cannot call the listen() method of QTcpServer without getting the error
QObject: Cannot create children for a parent that is in a different thread!
(Parent is QTcpServer …) …Because listen() appears to create a new QObject inside which tries to set the QTcpServer instance as parent!???
-
Try implementing a wrapper for the QTcpServer. Something like this:
@
class MyServer : public QObject
{
Q_OBJECT
public:
MyServer(QObject* a_parent);public slots:
void startServer();
void stopServer();
void handleNewConnection();
signals:
void newConnectionSg(QTcpSocket* a_pSocket);
private:
QTcpServer* m_pServer;
};MyServer::MyServer(QObject* a_parent)
: QObject(a_parent)
{
m_pServer = new QTcpServer(this);
connect(m_pServer, SIGNAL(newConnection()), this, SLOT(handleNewConnection()));
}void MyServer::handleNewConnection()
{
emit newConnectionSg(m_pServer->nextPendingConnection());
}void MyServer::startServer()
{
m_pServer->listen(QHostAddress::Any, 1234);
}void MyServer::stopServer()
{
m_pServer->close();
}
@
Then do this.
@
int main(int argc, char* argv[])
{
QApplication *a = new QApplication(argc, argv);QThread* thread = new QThread(a); MyServer* server = new MyServer(); server->moveToThread(thread); connect(thread, SIGNAL(started()), server, SLOT(startServer())); connect(thread, SIGNAL(finished()), server, SLOT(stopServer())); connect(thread, SIGNAL(finished()), server, SLOT(deleteLater())); connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); QTimer::singleShot(1000, thread, SLOT(start())); return a->exec(); }
@
BUT it really isn't neccessary to move the QTcpServer to another thread because of its asynchronous interface. What you could do is move the sockets that QTcpServer::nextPendingConnection() returns into threads of their own (again not neccessary for simple use cases because of asynchronous design).
-
In my framework i already got the sockets wrapped.
I also tried the same thing with QTcpSocket and connectToHost()
Same result.But i now found a way to get rid of the error!
I'm now calling listen() before calling move to thread!
@
int main(int argc, char* argv[])
{
QApplication *a = new QApplication(argc, argv);QThread* thread = new QThread(a);
QTcpServer* socket = new QTcpServer();
QObject::connect(thread, SIGNAL(finished()), socket, SLOT(deleteLater()));
QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));socket->listen(QHostAddress::Any, 1234);
socket->moveToThread(thread); //this line has to come AFTER calling socket->listen()
thread->start();
return a->exec();
}@I am testing the full functionality right now.
-
Just out of curiosity have you tried calling listen(..) after starting the thread ?
-
Calling listen AFTER staring the thread also worked!
-
Hmm must have got something to do with thread context I guess. If you call it before moveToThread it's executed in the context of the main thread (running eventloop) if you call it after starting your new thread it's executed in the new threads context (also running eventloop). If you call it in between moveToThread() and start() it's already in the new threads context but the eventloop of this thread is not running yet.
Just a guess though. I would really like to know the exact reason.
-
Yes me, too.
Ok. For the QTcpServer it works fine. The QTcpSocket gives me an error when sending/receiving stuff:
QSocketNotifier: socket notifiers cannot be enabled from another thread (????)What does that mean at all? Beside this error it is all working fine! It is sending and receiving and signals are sent and received!
-
OK. It is by the way senseless to put a socket into a thread!
I am now using the thread-worker approach and it is working perfectly. If a signal is connected to a QObject (the worker) which is in another thread (one can use QObject::moveToThread()) the signal will be appended to a queue. The thread worker will receive the signals when the previos signal has been proceeded completely!