【问题标题】:Access QTcpSocket from another thread (child thread)从另一个线程(子线程)访问 QTcpSocket
【发布时间】:2014-01-13 07:51:20
【问题描述】:

我创建了一个线程,其中包含一个接受任何传入连接的QTcpServer

void Service::run() //Service class is a subclass of QThread
{
    server->listen(QHostAddress::LocalHost, ServicePortNo);
    // server is a private member of Service    

    while(server->waitForNewConnection(-1)){
        QTcpSocket *socket = server->nextPendingConnection();
        handle(socket); // This is a pure virtual function
    }
}

handle(QTcpSocket *socket)

// TimeDateService is subclass of Service
// implementation of pure virtual function handle()
void TimeDateService::handle(QTcpSocket *socket)
{
    (new TimeDateSocketHandler(socket))->Start();
}

注意TimeDateSocketHandlerSocketHandler的子类,SocketHandler本身是QThread的子类,如下所示:

void SocketHandler::run()
{
    if(!socket->waitForReadyRead(WAIT_TIMEOUT))
    {
        socket->disconnectFromHost();
        socket->close();
        return;
    }
    QByteArray request = socket->readAll();
    QByteArray response = Serve(request); // Serve is a pure virtual function
    socket->write(response);
    socket->waitForBytesWritten(WAIT_TIMEOUT);
    socket->disconnectFromHost();
    socket->close();
}

最后是TimeDateSocketHandler

QByteArray TimeDateSocketHandler::Serve(QByteArray request)
{
    QByteArray response;
    response.append(QTime::currentTime().toString().toUtf8());
    response.append(QString(SEPARATOR).toUtf8());
    response.append(QDate::currentDate().toString().toUtf8());
    return response;
}

主要功能:

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    TimeDateService timedateService;
    //CalculatorService calculatorService;
    //RemoteCMDService remoteCMDService;

    timedateService.StartService();
    //calculatorService.StartService();
    //remoteCMDService.StartService();

    return a.exec();
}

main 函数中,我启动了TimeDateService。但是当我连接到服务器以检索时间和日期时,服务器会发送时间和日期,但是当TimeDateSocketHandler 想要关闭套接字时,程序崩溃了:

QCoreApplication::sendEvent 中的 ASSERT 失败:“无法将事件发送到 由不同线程拥有的对象。当前线程 3998779bf0。 接收器“”(类型为“QNat iveSocketEngine”)是在线程中创建的 39985efcd0",文件 kernel\qcoreappplication n.cpp,第 494 行

谁能帮我解决这个问题,非常感谢

【问题讨论】:

  • 请显示您的主要功能(包含实例化和连接)。另外,最好不要继承 QThread...
  • @LaszloPapp 感谢您的回复,我已经更新了问题帖,请查看

标签: c++ qt qthread qtcore qtnetwork


【解决方案1】:

你的问题是这一行:

(new TimeDateSocketHandler(socket))->Start();

父“socket”存在于 TimeDateService 线程中,而子“socket”将存在于 TimeDateocketHandler 线程中。使用 Qt 事件循环时,父子节点应该在同一个线程中。

这里是documentation的相关部分:

所有线程都支持事件过滤器,但监控对象必须与被监控对象位于同一线程中。类似地,QCoreApplication::sendEvent()(与 postEvent() 不同)只能用于将事件分派到位于调用函数的线程中的对象。这是一个例子:

解决方案比较简单:

  • 您可以直接使用invokeMethod method of QMetaObject 调用该方法。您需要使用排队连接来在单独的线程中触发插槽。

    QMetaObject::invokeMethod(new TimeDateSocketHandler(socket), 插槽(开始()), Qt::QueuedConnection);

  • 使用信号和插槽。这意味着发出一个信号而不是直接调用,然后连接另一个线程的相应槽。

    TimeDateSocketHandler *timeDateSocketHandler = new TimeDateSocketHandler(socket);

    connect(this, SIGNAL(socketHandled()), timeDateSocketHandler, SLOT(Start()));

    发出socketHandled();

  • 使用智能指针(如 QSharedPointer)而不是原始指针

  • 将套接字处理移至另一个线程。

【讨论】:

  • 感谢您的回答!但我想在单独的线程中处理每个套接字(传入连接)以避免服务器阻塞。你能帮我解决这个问题吗
  • 对不起,亲爱的 Laszlo,我是 Qt 中的多线程新手,你能解释一下第二种解决方案吗
  • @ABFORCE:完成,但您应该使用第三种解决方案。
  • 我尝试了第三种解决方案,但出现错误:error: C2243: 'type cast' : conversion from 'TimeDateSocketHandler *' to 'QObject *' exists, but is inaccessible
  • 好吧,您还没有显示所有相关代码。自然,TDSH 需要在某个地方继承 QObject,其中包含 Q_OBJECT 宏以及调用者线程类等。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-30
  • 1970-01-01
  • 1970-01-01
  • 2018-09-22
  • 2014-07-13
相关资源
最近更新 更多