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