3

プロデューサーオブジェクトによって処理される一部のHWからのリアルタイムデータのストリームがあります。これは、GUIの応答性を維持するために、独自のスレッドで処理するコンシューマーに接続されます。

mainwindow::startProcessing(){
    QObject::connect(producer,SIGNAL(dataReady(data*),consumer,SLOT(doData(data*)));
    consumer->moveToThread(&consumerThread);        
    consumerThread.start(); 
}

mainwindow::stopProcessing(){
    producer->disconnect(SIGNAL(dataReady(data*));
    consumer->cleanup();                        
    delete consumer;
}

consumer::doData(data* x) {
    mutex.lock();
    processingObject stuff
    mutex.unlock()
}

consumer::cleanup() {
     mutex.tryLock();
      .... blah ....
      delete processingObject; // then doData gets called again
}

私の問題は、コンシューマーオブジェクトを破棄した後でも、切断を行った後でもシグナルが送信されることです。これを停止するために、ますます複雑になるミューテックスのセットを試しましたが、理想的な解決策は、すべての未処理のシグナルが処理されるまでクリーンアップを待機することです。

スロットにキューに入れられている未処理の信号の数を監視する方法はありますか?またはとにかくそれらをクリアするには?

4

3 に答える 3

3

コンシューマーオブジェクトを、それが存在するスレッドとは異なるスレッドから破棄しているようです。通常、QObjectは、正しいスレッドで実行された場合、破棄時にすべての切断とイベントキューのクリアを処理します。Qtのドキュメントから:

オブジェクトを所有しているスレッド以外のスレッドからQObjectに対してdeleteを呼び出す(または他の方法でオブジェクトにアクセスする)ことは、オブジェクトがその時点でイベントを処理していないことを保証しない限り、安全ではありません。代わりにQObject::deleteLater()を使用すると、DeferredDeleteイベントが送信され、オブジェクトのスレッドのイベントループが最終的に取得します。

クリーンアップをコンシューマーのデストラクタに入れてQMetaObject::invokeMethod(consumer, "deleteLater");、コンシューマーが自分のスレッド内から自分自身を破壊するようにするために使用します。スロットでinvokeMethodを使用すると、スレッドセーフな方法でdeleteLaterの呼び出しが送信されます。これは、deleteLater自体がスレッドセーフであるというドキュメントがないため、必要なようです。コンシューマーが破棄されるまでブロックする必要がある場合は、接続タイプをに指定できますがQt::BlockingQueuedConnection、それ以外の場合は、のデフォルトでQt::AutoConnection問題ありません。

于 2012-08-01T21:38:28.467 に答える
2

ここでの問題は接続の種類ですデフォルトのタイプの接続を使用するため、ですQt::AutoConnection。異なるスレッドからオブジェクトを接続しているので、これはとして機能しQt::QueuedConnectionます。

今、私はあなたのプロデューサーがあなたの消費者がそれらを食べるよりも速くデータを作成すると仮定します。これにより、コンシューマスレッドのイベントキューにデータがバッファリングされます。したがって、シグナルを切断すると、実際には切断されますが、イベントキューで待機している大量のデータがあり、まだ接続されていることだけが満たされます。

それを修正する方法は?コンシューマーを高速化するか、コンシューマーにフラグを追加します。これにより、コンシューマースロットに着信するデータが無視されます。または、プロデューサーを遅くします。別のコミュニケーションパターンを試してください。または、ジョブを複数のスレッドに分割する同時APIを使用します。最善の解決策は、何をしているかの詳細によって異なります。

幸運を。

于 2012-08-01T22:13:29.237 に答える
1

信号を複数回接続していないことを確認してください。接続していない場合は、このメーリングリストのアーカイブを確認すると、ヒントや提案が得られる可能性があります。

http://lists.trolltech.com/qt-interest/2000-05/thread00051-0.html

要するに多分試してみてください:

mainwindow::stopProcessing()
{
    // Block the producer's signals. 
    producer->blockSignals( true );

    // Perform clean up/stop
    consumer->cleanup();

    // Delete the consumer, this disconnects all signals connected 
    // to the consumer.
    delete consumer;

    // Restore the producer's signals
    producer->blockSignals( false );
}

編集:blockSignals呼び出しを修正しました。コンシューマーではなくプロデューサーにある必要があります。

于 2012-08-01T19:53:27.667 に答える