2017-10-27 5 views
0

私は現在の仕事で複雑なプログラムを継承しており、QTcpSocketを経由してくるデータの流れからイメージのちらつきを減らそうとしています。QTcpSocket経由のデータストリームから複雑なアルゴリズムを連続して実行するための最適なQTスレッディングソリューションは何ですか?

プログラムは連続したデータストリームを受け取り、それを処理してからpaintEventで画面にペイントします。

処理機能は、信号がQTcpSocketからのreadyread()であり、スロットがデータ処理機能である信号/スロット接続に基づいて実行されます。ストリームは連続的なので、この信号/スロットは着信データに基づいてスクリーン上のペイントされた画像を連続的に発射し更新する。

イメージが瞬時にちらつき、メインイベントループの処理がデータストリームに干渉している可能性があるので、私の考えはデータ処理機能を独自のスレッドに入れることでした。このデータ処理関数は、プログラムの他の機能に完全に統合されているため、この時点でデータストリームをサブクラス化して、QThreadを適用することはできません。また、プログラム全体の完全なリストアになります。 。

だから、私の考えはそうのようなQtConcurrentを使用していた:

connect(tcpSocket2, SIGNAL(readyRead()), this, SLOT(getData())); 

だから私は(SLOTを置き換え:のgetData()はreadyread()信号に接続されたデータ処理機能である

void MainWindow::getDataThread(){  //implemented as a slot 
    wpFuture = QtConcurrent::run(this, &MainWindow::getData); 
} 

getData())とSLOT(getDataThread())を使用して、グローバルスレッドプールから取得された新しいスレッドでデータ処理関数を実行できるようにします。ストリームは連続しているので、getData処理関数が実行されるたびに常に新しいスレッドが割り当てられていると思います。ちらつきを減らすように見えますが、約30〜60秒後にプログラムはランダムにクラッシュし、特定の吹き出しは発生しません。

私の質問は:データストリームをサブクラス化せずに、自分のデータ処理機能をスレッドするためのより良い方法はありますか?この特定の状況でQtConcurrentを実装する際に私の思考や理解が間違っていますか?

ありがとうございます。

+0

通常、ダブルバッファリングでちらつきが解決されます。https://doc.qt.io/archives/qq/qq06-flicker-free.html – WindyFields

+0

また、複数のスレッドから同時にMainWindow :: getDataを呼び出すと安全?あなたのプログラムがシングルスレッドだったのであれば、おそらくスレッドセーフではありませんでした。 – WindyFields

+0

ありがとう、私はダブルバッファリングを確認します。複数のスレッドに関しては、ソケット上でデータが検出されるたびにQtConcurrent :: runが実行されていました。いったんQtConcurrentがスレッド上で関数を実行し、関数が完了すると、グローバルスレッドプールにスレッドを返すので、各反復は関数にスレッドを割り当て、スレッドを解放し、スレッドを割り当て、リリースします。これは、一度にMainWindow :: getData関数に対して実行されるスレッドが1つだけであることを意味します。私はこれが最善の方法ではないと考えています。 –

答えて

0

あなたのご意見からは、スレッドプールの理解が間違っていると思います。

スレッドプールには多数のスレッドがあります。 QtConcurrent::runを呼び出すたびに、グローバルスレッドプールから空きスレッドが取得され、実行するタスクが渡されます(MainWindow::getData)。 MainWindow::getDataが(おそらく)異なるスレッドで実行されるたびにQtConcurrent::runを何度も呼び出すと、スレッドプールに現在使用可能なスレッドがない場合、タスクはキューに入れられ、後で利用可能になるとスレッドに渡されます。この方法では、スレッドプール内のスレッドの数によって制限された複数の同時実行タスクを実行できます。

今や問題は、MainWindow::getDataはおそらくその設計上スレッドセーフではないということです。数回呼び出されたQtConcurrent::run(this, &MainWindow::getData);は、データ競合につながる可能性があります。

あなたはデータを処理するために別個の単一スレッドはその後、ちょうど(何でも「サブクラス」する必要はありません)QThreadを使用する場合:contextオブジェクトが生きているとthreadが毎回QTcpSocket::readyReadを実行している

// A thread and its context are created only once 
QThread thread; 
QObject context; 
context.moveToThread(&thread); 
// ... 

QObject::connect(tcpSocket2, &QTcpSocket::readyRead, &context, [this]() { 
    this->getData(); 
}, Qt::QueuedConnection); 

thread.start() 

限りemmited - ラムダが実行されます。

ワーカースレッドとメインスレッドが、getDataに衝突しないように注意してください。

+0

QtConcurrentが実行するように割り当てられた関数(この場合はgetData())が完了すると、そのスレッドはスレッドプールに戻されません。 –

+0

スレッドを戻します。しかし、 'QtConcurrent :: run'を2度目に呼び出すと、以前の' getData() '呼び出しはすでに完了していることが保証されていますか?それとも私が逃した何かがありますか? – WindyFields

+0

readyread()シグナルをカスタムスロット機能にアタッチすると、シグナルが再び発生する前にスロット機能が完了する必要があるという前提がありました(マニュアルでは見つからないため)。再度、私はドキュメンテーションでそれを見つけることができなかったので、それは私の誤解である可能性があります。正しい解決策を導いてくれたので、あなたの答えを正しいものとして受け入れるつもりです。最終的には、スレッド化よりもダブルバッファリングを検討する必要があったはずですが、サブクラス化する必要がないスレッディング例も提供しました。私はあなたの助けに感謝します! –

関連する問題