Qt QTcpSocket与QtConcurrent :: run需要事件循环在单独的线程中

时间:2013-02-12 19:11:06

标签: qt qthread qtcpsocket qtconcurrent qtembedded

我在Qt中有一个Web服务器,它将读取一个非常大的(~1Gb)文件,并通过QTcpSocket将数据返回给请求者。此套接字由主服务器线程创建。我想使用QtConcurrent将此套接字移交给工作线程并将数据发送回那里。

// Using QtConcurrent
BackgroundConcurrent childThreadToReturnLotsOfData;
QFuture<void> futureObject = QtConcurrent::run(&childThreadToReturnLotsOfData, &BackgroundConcurrent::returnPartialLargeFile, resp , &fileToCheckExistence);

我的'returnPartialLargeFile'函数如下所示:

void BackgroundConcurrent::returnPartialLargeFile( QHttpResponse *resp , QFile *fileToCheckExistence  ) const
{

    // We need an event loop for the QTCPSocket slots
    QEventLoop loop;
    //QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
    // Execute our event loop
    //loop.exec();

    // To do this in another thread from the one created, you must
    // move that socket to this thread, reparent and move
    resp->m_connection->m_socket->setParent( 0 );
    resp->m_connection->m_socket->moveToThread( QThread::currentThread() );

    // Read in chunks until we have sent all data back to the requestor
    QByteArray dataToWriteToSocket; // Store the data to send back
    while ( dataReadFromFileInBytes > 0 ) {

        // Read some Data into the byte array

        // Write each chunk to the socket
        resp->write(dataToWriteToSocket); // <----- Here is our data from the content of the file
        resp->flushData(); // <----- Flush data to the socket

    }

    // End our response and close the connection
    resp->end();
    return;

}

我得到的错误是,如果我将“loop.exec()”行注释掉,我会收到以下错误:

ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread. Current thread c2630. Receiver '' (of type 'QTcpServer') was created in thread 910a8", file kernel/qcoreapplication.cpp, line 501

如果我取消注释它,那么我的函数在exec()行短路并且永远不会写入和数据到套接字,但我没有得到任何错误,我只是得到一个截断的响应,不包括来自while循环。

我正在重新定义套接字并将其移动到新线程,所以我希望我的问题只有事件循环和套接字信号和插槽。我在这里做错了什么想法?我怎样才能让它发挥作用?如果发出信号/插槽,我需要在这里连接吗?谢谢 -

2 个答案:

答案 0 :(得分:1)

所以你要做的是写入while循环中新线程中的响应。

在这种情况下,您不需要moveToThread。

新线程可以对主线程拥有的对象进行操作。只要没有比赛。

如果两个线程都在套接字上运行,那么您需要一个互斥锁。即使您将套接字移动到新线程,如果存在竞争,您还需要一个互斥锁来防止数据竞争。

Qt提供了一些关于线程的非常好的文档。

阅读this以了解何时需要moveToThread,以及this了解如何进行线程同步。如果您想了解有关Qt中线程的更多信息,那么所有these都值得一读。

答案 1 :(得分:1)

如果您只是按照建议移除moveToThread,如果套接字太早被另一端断开连接,则此代码将会死亡,并且写入失败。因为写将关闭将删除套接字通知程序,并且您将命中断言&#34;无法将事件发送到由不同线程拥有的对象&#34;。我知道,因为我只是打了它......

你应该做什么(我在https://github.com/KDAB/KDSoap/blob/master/src/KDSoapServer/KDSoapServerThread.cpp中做的)是将套接字描述符(int)传递给辅助线程,这将创建套接字本身。然后所有套接字处理都在辅助线程中完成,连接,读/写,断开连接。 Qt会很高兴,没有线程违规。

相关问题