4

Qtに非常に大きな(〜1Gb)ファイルを読み取り、QTcpSocketを介してデータをリクエスターに返すWebサーバーがあります。このソケットは、メインサーバースレッドによって作成されます。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を削除しただけでは、ソケットがもう一方の端で切断されるのが早すぎると、このコードは停止し、書き込みが失敗します。書き込みが閉じてソケット通知機能が削除され、「別のスレッドが所有するオブジェクトにイベントを送信できません」というアサートが発生するためです。私はちょうどそれを打ったので、私は知っています...

代わりに行うべきこと(https://github.com/KDAB/KDSoap/blob/master/src/KDSoapServer/KDSoapServerThread.cppで行います)は、ソケット記述子(int)をセカンダリスレッドに渡すことです。ソケット自体。次に、すべてのソケット処理がセカンダリスレッドで実行され、接続、読み取り/書き込み、切断が行われます。そして、Qtは満足し、スレッド違反はありません。

于 2016-02-19T12:01:35.580 に答える