4

我在 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 循环的任何数据的截断响应.

我正在重新设置套接字并将其移至新线程,因此我希望我的问题仅与事件循环以及套接字信号和插槽有关。关于我在这里做错了什么的任何想法?我怎样才能让它工作?如果信号/插槽问题,我需要在这里连接哪个?谢谢 -

4

2 回答 2

1

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

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

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

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

Qt 有几个关于线程的非常好的文档。

阅读本文以了解何时需要 moveToThread,以及如何进行线程同步。如果您想进一步了解 Qt 中的线程,所有这些都值得一读。

于 2013-03-01T00:46:46.543 回答
1

如果您只是按照建议删除 moveToThread,则此代码将在另一端过早断开套接字并且写入失败的情况下终止。因为 write 将关闭,这将删除套接字通知程序,并且您将点击断言“无法将事件发送到其他线程拥有的对象”。我知道,因为我刚刚击中它...

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

于 2016-02-19T12:01:35.580 回答