Step 1: do not use threading for socket communication unless you absolutely need to use blocking functions.
Why do you think you need threads?
Ok, now what is wrong with your code. At first sight nothing, but in the background there's a huge problem.
Let's break up your code:
class MessageThread
: public QThread{
...
};
class MessageThread : public QThread
{
...
};
To copy to clipboard, switch view to plain text mode
Your MessageThread class is a subclass of QThread.
A QThread subclass is NOT a new thread. Any MessageThread object lives in the main GUI thread. Keep that in mind for the next lines of code.
public slots:
void newMessConnection();
signals:
public slots:
void newMessConnection();
signals:
void error(QTcpSocket::SocketError socketError);
To copy to clipboard, switch view to plain text mode
These signals and slots, which you define in your QThread subclass are emitted and called inside the main GUI thread since the QThread object lives in the main gui thread. Try to understand this when we look at the next few lines of code.
void MessageThread::run()
{
messageSrv = messageServer;
connect(messageServer, SIGNAL(newConnection()), this, SLOT(newMessConnection()));
}
void MessageThread::run()
{
QTcpServer* messageServer = new QTcpServer;
messageSrv = messageServer;
connect(messageServer, SIGNAL(newConnection()), this, SLOT(newMessConnection()));
}
To copy to clipboard, switch view to plain text mode
The code in the run() function is being run in a separate thread. So far that's a good idea. You define a new QTcpServer object inside this new thread. So far that's also good. You might want to write messageSrv = new QTcpServer directly though. The problems begin with the connection of the signal and the slot.
The signal newConnection() is being emitted in another thread than the slot newMessConnection(). The slot newMessConnection lives in the main gui thread. Ok, so far that's not a big problem as you want to have some feedback to your main thread.
However, let's look what happens in the slot itself:
void MessageThread::newMessConnection()
{
QTcpSocket* connection
= messageSrv
->nextPendingConnection
();
}
void MessageThread::newMessConnection()
{
QTcpSocket* connection = messageSrv->nextPendingConnection();
}
To copy to clipboard, switch view to plain text mode
The connection object is a huge problem. Remember, as I already mentioned several times, the newMessConnection lives in the main gui thread!!!. BUT, messageSrv points to an object in another thread!!!
This is an error!.
This is the exact reason why you get the following error:
QObject: Cannot create children
for a parent that is in a different thread.
QObject: Cannot create children for a parent that is in a different thread.
To copy to clipboard, switch view to plain text mode
Solution, in pseudo code:
class MyConnection
: public QObject{
Q_OBJECT
public slots:
void newConnection();
signals:
void error();
};
Then when you use your connection:
MyConnection *connection = new MyConnection;
connect(connection, SIGNAL(error()), this, SLOT(handleError()));
connection->moveToThread(connectionThread);
class MyConnection : public QObject
{
Q_OBJECT
public slots:
void newConnection();
signals:
void error();
};
Then when you use your connection:
MyConnection *connection = new MyConnection;
connect(connection, SIGNAL(error()), this, SLOT(handleError()));
QThread *connectionThread = new QThread;
connection->moveToThread(connectionThread);
To copy to clipboard, switch view to plain text mode
Edit: Since this question gets asked a lot and since the Qt documentation, at the moment, isn't very clear on this complexity, I'll write a wiki tutorial on threading and sockets this week.
Bookmarks