Reputation: 75
I'm trying to develop a threaded server that contains a run method which is to run in another thread with QtConcurrent::run.
Am I right, when I don't create a server that doesn't inherit from QTcpServer and just uses an object of QTcpServer.
Is it wrong to run only one method in a other thread? Because I’ve learned it to do it like this in C# and in other Qt examples they put the current object in a other thread.
Why do I get this message:
QObject: Cannot create children for a parent that is in a different thread. (Parent is MyServer(0x1ab1ca0), parent's thread is QThread(0x187a840), current thread is QThread(0x1acfa90)
When I start the run method.
Here is the source code:
myserver.h
#ifndef MYSERVER_H
#define MYSERVER_H
#include <QObject>
#include <QtNetwork/QTcpServer>
#include <QtConcurrentRun>
#include <QFuture>
#include "myclienthandle.h"
class MyServer : public QObject
{
Q_OBJECT
public:
explicit MyServer(QObject *parent = 0, const QString &ip = "Any", int port = 0);
explicit MyServer(const MyServer &server);
~MyServer();
QString IP() const;
void setIP(const QString &ip);
int Port() const;
void setPort(int port);
bool isAlive() const;
private:
QTcpServer *m_qtcpserListener;
QFuture<void> m_qftrRun;
QString *m_qstrIP;
int m_iPort;
int m_iClientID;
bool m_bRun;
void run();
signals:
void newConnection(MyClientHandle *clientHandle);
public slots:
void start();
void stop();
};
inline QString MyServer::IP() const
{
return *m_qstrIP;
}
inline void MyServer::setIP(const QString &ip)
{
m_qstrIP = new QString(ip);
}
inline int MyServer::Port() const
{
return m_iPort;
}
inline void MyServer::setPort(int port)
{
m_iPort = port;
}
inline bool MyServer::isAlive() const
{
return m_bRun;
}
#endif // MYSERVER_H
myserver.cpp
#include "myserver.h"
MyServer::MyServer(QObject *parent, const QString &ip, int port) :
QObject(parent), m_iClientID(0), m_bRun(false), m_qtcpserListener(0)
{
setIP(ip);
setPort(port);
}
MyServer::MyServer(const MyServer &server)
{
MyServer(server.parent(), server.IP(), server.Port());
}
MyServer::~MyServer()
{
if (m_qtcpserListener != 0)
stop();
}
void MyServer::run()
{
m_qtcpserListener = new QTcpServer(this);
if (!m_qtcpserListener->listen(QHostAddress(IP()), Port()))
{
return;
}
while (m_bRun)
{
if (m_qtcpserListener->waitForNewConnection(5000))
{
QTcpSocket *qtcpsoNextPending = m_qtcpserListener->nextPendingConnection();
emit newConnection(new MyClientHandle(qtcpsoNextPending));
}
}
}
void MyServer::start()
{
m_bRun = true;
m_qftrRun = QtConcurrent::run(this, &MyServer::run);
}
void MyServer::stop()
{
m_bRun = false;
if (m_qtcpserListener != 0 && m_qtcpserListener->isListening())
{
m_qtcpserListener->close();
}
m_qftrRun.cancel();
m_qftrRun.waitForFinished();
}
Thank you for your help.
Upvotes: 1
Views: 1424
Reputation: 14941
Your problem is that you are running the MyServer::run
function in a different thread (via QtConcurrent::run
, but in the MyServer::run
function you create a new TcpServer and give it a parent. In Qt, the parent of an object created in one thread (the concurrent one) can't be an object owned by another thread (whatever thread the instance of MyServer
is in, probably the first thread).
If you got past that, emitting signals in a different thread than the signaling object can also cause problems. You may also run into problems in deletion, since you shouldn't delete a QObject in a different thread than the one that owns it.
My suggestion is to use QTcpServer
's built-in threaded mechanism. When you call listen
, the function will return. You could then connect to the newConnection()
signal to be notified when there is a connection pending, instead of waiting for a connection (which is what might lead you to think you needed to run the function concurrently).
Upvotes: 2