あなたはそれをやり過ぎていると思います。Qtの美しさは、あなたがやろうとしていることがとても簡単であるという事実にあります。
QTimer
あなたは、コールバックを実行するために、実行中のスレッドを何らかの形で魔法のように中断すると考えているようです。これはQtでは決して当てはまりません。Qtでは、すべてのイベントとシグナルがスレッドで実行されているイベントループに配信され、そのイベントループがそれらをQObjectsにディスパッチします。したがって、スレッド内では、Qtのイベントおよびシグナル/スロットフレームワークによる同時実行の危険はありません。また、スレッド間で通信するためにQtのシグナルスロットとイベントメカニズムに依存している限り、各スレッド内でシリアル化されるため、他のアクセス制御プリミティブを使用する必要はありません。
したがって、問題は、スレッドでイベントループを実行しないことです。そのため、タイムアウトイベントが取得されて、timeout()
信号に接続したスロットにディスパッチされることはありません。
AQTimer
は、開始するスレッドがタイマーが存在するスレッドである限り、任意のスレッドで作成および開始できますQObject
。QObjectは、を使用して別のスレッドに移動しない限り、作成したスレッドに属しますQObject::moveToThread(QThread*)
。
タイマーを開始するためにを使用するinvokeMethod
必要はまったくありません。結局のところ、タイマーはそれが存在するのと同じスレッドから開始しています。キューに入れられた信号スロット接続は、名前が示すように、信号をキューに入れます。具体的には、シグナルを送信するQMetaCallEvent
と、レシーバースロットが存在するQObjectのキューに入れられます。これを取得して呼び出しを実行するには、スロットオブジェクトのスレッドでイベントループを実行する必要があります。スレッド内の何かを呼び出してそのキューを空にすることは決してないため、timeout()
スロットを呼び出すことはできません。
静的メンバーの初期化の大失敗については main()
、メインスレッドにあるQObject内またはQObject内にTオブジェクト全体を自由に構築し、それを新しいスレッドに移動できます。これは、QtConcurrentを使用しない場合の方法です。 。QtConcurrentを使用する場合、実行可能な関数は任意の数のQObjectを構築および破棄できます。
コードを修正するには、ラムダはイベントループをスピンする必要があります。
[] () {
sapp s;
s.f();
QEventLoop l;
l.exec();
}
以下に、Qtで慣例的に行われる方法のSSCCEの例を添付します。QtConcurrentを使用したくない場合は、2つの変更があります。スレッドのイベントループのqApp->exit()
直後に変更する必要があります。それ以外の場合は、終了しません(どのように認識しますか?)。また、関数を終了する前にスレッドをオンにする必要があります。まだ実行中の関数を破棄するのは悪いスタイルです。exit()
a.exec()
wait()
main()
QThreads
これらのexit()
関数は、イベントループに終了を通知するだけであり、フラグを設定するものと考えてください。実際には何も終了しないため、CスタイルのAPIとは異なりますexit()s
。
QTimer
aはQObject
それ自体であることに注意してください。パフォーマンス上の理由から、タイマーが頻繁に起動する場合は、QBasicTimer
によって返されるタイマーIDの単純なラッパーであるを使用する方がはるかに安価QObject::startTimer()
です。次に、を再実装しQObject::timerEvent()
ます。このようにして、シグナルスロット呼び出しのオーバーヘッドを回避できます。経験則として、直接(キューに入れられていない)シグナルスロット呼び出しは、2つの1000文字のQStringを連結するのと同じくらいのコストがかかります。私のベンチマークを参照してください。
補足:短い例を投稿する場合は、コード全体を直接投稿する方が簡単な場合があります。これにより、すべてが1つのファイルに含まれている限り、将来失われることはありません。3つのファイルに100行のサンプルコードが散らばっているのは逆効果です。以下を参照してください。キーは#include "filename.moc"
の最後にありfilename.cpp
ます。また、Javaスタイルで、メソッドを一度に定義および宣言するのにも役立ちます。短くてわかりやすいという名目ですべて。結局のところ、これは一例です。
//main.cpp
#include <QtCore/QTimer>
#include <QtCore/QDebug>
#include <QtCore>
#include <QtCore/QCoreApplication>
class Class : public QObject
{
Q_OBJECT
QTimer timer;
int n;
private slots:
void timeout() {
qDebug() << "hi";
if (! --n) {
QThread::currentThread()->exit();
}
}
public:
Class() : n(5) {
connect(&timer, SIGNAL(timeout()), SLOT(timeout()));
timer.start(500);
}
};
void fun()
{
Class c;
QEventLoop loop;
loop.exec();
qApp->exit();
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QtConcurrent::run(&fun);
return a.exec();
}
#include "main.moc"