2012-04-13 3 views
1

私は興味深い問題があります。 Qtを使ったC++プロジェクトの作業。クロスプラットフォームのプロジェクトですが、Winで開発しています。Qthreadが効率よく作業を終了するようにC関数を待たせるには?

私はCスタイルのコールバック関数を持っています。それはCスタイルにする必要があります、私はそれについての選択肢がありません。 そのCスタイルのコールバック関数で行われた作業は重要で時間に敏感です。したがって、Qthreadスレッドは作業負荷に役立ちます。

私はQtスレッドで実行スキームを使用していません。むしろQThreadsの下に説明されているQThreadsを使用しています。明確にするためにhttp://qt-project.org/doc/qt-5.0/qthread.html#wait

、私のようなQThreadを使用しています:

QThread *thread = new QThread; 
Worker *worker = new Worker; 
worker->moveToThread(thread); 
thread->start(); 
QMetaObject::invokeMethod(worker, "doWork", Qt::QueuedConnection); 

スレッドは、アプリケーションの開始時に行われ、QMetaObject ::は、invokeMethodが供給されます。

Qコールは、QThreadスレッドが処理を完了するまで、「何か」(効率的な方法で)コールバック関数を持たないようにしてください。私は、コールバック関数がワーカースレッドとCPUのために競合しないような方法で待機するようにしたいと思います(ビジーなダミーループはありません)。私はsleep()のようなものを使うこともできますが、スレッドが「早く」終了すると無駄な睡眠になるので効率的ではありません。私は労働者からのシグナルを送ることを考えましたが、問題は私のコールバックがC関数なので、Qtシグナルをどのように捕まえることができないのか分かりません。

+1

Can'tあなたはそこにQtのクラスとキャッチ信号とC-機能をラップ? – dvvrd

+0

いいえ、できません。 C関数は単なるC関数ではなく、コールバック関数です。 libの一部。私はその性質を変えることはできません、私はその体を実装することしかできません。私は何/誰がコールバックを呼び出す権限がありません、私はそれをCのコールバック関数を保持する必要があります。 – L123

答えて

0

さて、このようなアプローチを考えてみましょう。コールバック関数は、グローバルないくつかのフラグ(またはいくつかのカウンタをインクリメント)を設定する以外は何もしないで、関数が呼び出されたかどうか(または何回)表示されるかを示します。次に、QObjectから継承したimlementクラス(スロットを持つ)。あなたはそれをスレッド終了シグナルに登録します。シグナルが出力されると、あなたはコールバック関数のロジックを持つ別の関数をlibで呼び出された回数だけ呼び出すだけです。それは働くでしょうか?

+0

ハンマーを使って貯金箱にコインを入れたように聞こえます。 –

+0

ええ、それはこのように聞こえるが、要件を満たしている。「コールバック機能を、それがCPUと競合しないように待たせたいワーカースレッド(だからビジーダミーループ)。 – dvvrd

+0

ありがとうございますが、これはコールバックが既に外部ソース(OS)で始まるために呼び出されたため動作しません...これはすべてのための触媒であり、私はまだ終了してからコールバック関数をブロックする方法が必要です仕事が終わる前に – L123

0

"手元にある"スレッドがあり、作業が完了したらスレッドが終了することを完全に確信している場合。

http://qt-project.org/doc/qt-4.8/qthread.html#wait

しかし!

あなたは労働者がいくつかの葛を放出するまで、あなたがそのような何かがあり、あなたのスレッドが終了したい、とだけ待ちたくない場合は、次の

QEventLoop loop; 
connect(worker, SIGNAL(workFinished()), &loop, SLOT(quit())); 
QMetaObject::invokeMethod(worker, "doWork", Qt::QueuedConnection); 
loop.exec(); 
+0

はい、私は新しいスレッドを作ることは費用がかかるので、スレッドが死ぬことを望んでいません。 1人以上の労働者がいる場合、これはどのように機能しますか?作業者の1人が終了した後、イベントループが終了するようです。 – L123

+0

次に、あなた自身のためにいくつかの "プール"オブジェクトを作成し、すべてのワーカーについて知り、それらの追跡を維持する必要があります。それはQEventLoopを使用してaproach自体を使用し、すべての作業者が終了したかどうかを確認するだけです –

0

を質問が静かな古いですが、それは中に思いつきました"関連する質問"。この質問は興味深いので、答えはQtユーザーにとって便利なことかもしれないので、私は詳細な答えを与えることに決めました。完了するために別のQThread内の関数を待つ行うに

、複数の戦略が考えられます

  1. 使用Qt::BlockingQueuedConnection
  2. 純粋なwhile(anAtomicBoolean){}ループを使用してください。
  3. 少し巧妙なループwhile(anAtomicBoolean){QThread::yieldCurrentThread();}を使用してください。
  4. QWaitConditionを使用してください。
  5. QSemaphoreを使用してください。

戦略2と3はループ状態をチェックするのを待っている間待機スレッドがアクティブでなければならないため、悪い考えです。しかし、戦略3では、他のスレッドやプロセスのCPU時間を解放するという利点があります。

他の3つの戦略は、待機中にスレッドを休止させるという利点があり、かなり同等でなければなりません。しかし、ソリューション1と4では、複数のワーカーを異なるスレッドで同時に実行することはできません(少なくとも簡単には)。だから最高の解決策は、セマフォと一緒に行くことです。私は(誰かが興味を持っている場合、私は、後にコードが利用できるようになります)少しベンチマークをした私の主張を証明するために

QSemaphore semaphore(2) 
worker1.sem = &semaphore; 
worker2.sem = &semaphore; 
semaphore.acquire(2); 
QMetaObject::invokeMethod(&worker1, "doWork", Qt::QueuedConnection); 
QMetaObject::invokeMethod(&worker2, "doWork", Qt::QueuedConnection); 
semaphore.acquire(2); // each worker release(1) when done 
semaphore.release(2); 

。私はQueryThreadCycleTime()を使用して、待ちスレッドによって消費されたサイクル数を取得しました。このように:

QueryThreadCycleTime(hThread, &start); 
QMetaObject::invokeMethod(&worker, "doWork", Qt::BlockingQueuedConnection); 
QueryThreadCycleTime(hThread, &stop); 

ベンチマーク結果を以下のグラフに示されている: Result graph

関連する問題