Многопоточный сервер с QtConcurrent :: run - PullRequest
1 голос
/ 16 июня 2011

Я пытаюсь разработать многопоточный сервер, содержащий метод run, который должен запускаться в другом потоке с помощью QtConcurrent :: run.

Мой первый вопрос:

Прав ли я, когда я не создаю сервер, который не наследует от QTcpServer и просто использует объект QTcpServer.

Второй вопрос:

Неправильно ли запускать только один метод в другом потоке? Потому что я научился так делать в C # и в других примерах Qt они помещают текущий объект в другой поток.

Третий вопрос:

Почему я получаю это сообщение:

QObject: Невозможно создать дочерние объекты для родитель, который находится в другой теме. (Родитель - MyServer (0x1ab1ca0), родительский поток - QThread (0x187a840), текущий поток - QThread (0x1acfa90)

Когда я запускаю метод запуска.

Вот исходный код:

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();
}

Спасибо за вашу помощь.

1 Ответ

1 голос
/ 16 июня 2011

Ваша проблема в том, что вы запускаете функцию MyServer::run в другом потоке (через QtConcurrent::run, но в функции MyServer::run вы создаете новый TcpServer и присваиваете ему родительский тип. В Qt, родительском объекте объект, созданный в одном потоке (параллельный), не может быть объектом, принадлежащим другому потоку (независимо от того, в каком потоке находится экземпляр MyServer, возможно, первый поток).

Если вы преодолели это, передача сигналов в потоке, отличном от объекта сигнализации, также может вызвать проблемы. Вы также можете столкнуться с проблемами при удалении, поскольку не следует удалять объект QObject в другом потоке, чем тот, которому он принадлежит.

Я предлагаю использовать встроенный резьбовой механизм QTcpServer. При вызове listen функция вернется. Затем вы можете подключиться к сигналу newConnection(), чтобы получать уведомления при ожидании соединения, вместо того, чтобы ждать соединения (что может заставить вас думать, что вам необходимо запустить функцию одновременно).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...