Paul Kreker
Paul Kreker

Reputation: 75

Threaded Server with QtConcurrent::run

I'm trying to develop a threaded server that contains a run method which is to run in another thread with QtConcurrent::run.

My first question is:

Am I right, when I don't create a server that doesn't inherit from QTcpServer and just uses an object of QTcpServer.

Second question:

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.

Third question:

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

Answers (1)

Caleb Huitt - cjhuitt
Caleb Huitt - cjhuitt

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

Related Questions