1

MainWindowのコンストラクターで作成された2つのQObject間でシグナル/スロットを接続するためのベストプラクティスを知りたかったのですが、後で別のスレッドに移動しました...デフォルトの接続が機能していないようですが、オプションで接続すると機能しQt::Directconnection始めます...しかし、シグナル/スロットが失敗することがあります...以下は私のコードパターンです..クラスの設計を変更する必要がある場合はお知らせください...

MainWindow.cpp

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
{
   myObjectA = new ObjectA;
   myObjectB = new ObjectB;

   connect( myObjectA,SIGNAL(signalA()),myObjectB,SLOT(slotB()) );

   myObjectA.initiateProcess();
   myObjectB.initiateProcess();
}

ObjectA.h

#include <QThread>
#include <QObject>

class ObjectA : public QObject
{
    Q_OBJECT
public:
    explicit ObbjectA(QObject *parent = 0);
    void inititateProcess();
public slots:
    void do_job();

signals:
    void signalA();
private:
    QThread *worker;
}

ObjectA.cpp

ObjectA::ObjectA(QObject* parent)
{
  ....
}

void ObjectA::do_jobA()
{
  //do something;
}

void ObjectA::initiateProcess()
{
  worker = new QThread;
  connect(worker,SIGNAL(started()),this,SLOT(do_jobA()));
  this->moveTo(worker);
  worker->start()
}

ObjectB.h

#include <QThread>
#include <QObject>

class ObjectB : public QObject
{
    Q_OBJECT
public:
    explicit ObjectB(QObject *parent = 0);
    void initiateProcess();
public slots:
    void do_job();
    void slotB();

signals:
    void signalB();//for some other slot
private:
    QThread *worker;
}

ObjectB.cpp

ObjectB::ObjectB(QObject* parent)
{
  ....
}

void ObjectB::do_jobB()
{
  //do something;
}

void ObjectB::initiateProcess()
{
  worker = new QThread;
  connect(worker,SIGNAL(started()),this,SLOT(do_jobB()));
  this->moveTo(worker);
  worker->start()
}
4

2 に答える 2

4

一般に、個人的な意見として、スレッド内であっても、ブロッキングコード(そのようなQWaitCondition)とイベントループを混在させることはありません。ただし、長時間ブロックしないことがわかっている場合を除きます。GUIスレッドの場合、「長い」は100ミリ秒を超えると思います(それより長く、従来のデスクトップアプリでもユーザーエクスペリエンスが低下し始めます)が、他のスレッドの場合は、問題がない時間によってははるかに長くなる可能性があります。スレッドが処理する必要のあるイベントとシグナル。

複数のスレッドを使用する場合は、通常、シグナルに自動接続または明示的にキューに入れられた接続を使用することをお勧めします。直接接続は、シグナルが発行されるスレッドで実行されます。受信オブジェクトが別のスレッドに存在する場合、スロット(および結果として、クラスに関連するすべてのもの)をスレッドセーフにする必要があります。そのようにしない方がはるかに簡単で安全であり、追跡することが1つ少なくなります。

現在1つのスレッドでコードを記述しているが、後で別のスレッドに移動する準備をしたい場合は、接続をキューに入れる方がよいでしょう。そうすれば、動作はシングルスレッドでもほぼ同じになり、emitすぐに戻り、後で驚くことはありません。

スレッドで不確定またはその他の方法で長時間ブロックするコードを記述したい場合は、サブクラスQThread化してオーバーライドQThread::run()し、呼び出さない方がよいでしょうexec()。次に、独自のループでQMutexとQWaitConditionを使用するか、他の「従来の」スレッド間通信方法を使用できます。スレッドからシグナルを送信することはできますが、スレッドの問題を回避するために接続をキューに入れる必要があります。また、QThreadに追加するスロットは、run()メソッドが実行されているスレッドではなく、QThreadオブジェクトが存在するスレッドで実行する必要があることにも注意してください。run()これは実際には非常に便利なパターンです。ロックしないように注意する限り、QThreadサブクラスのスロットにある実際のスレッドインタラクションコードをすべて「非表示」にすることができます(実行されるスレッドでは実行されないことに注意してください)。QMutexあまりにも長い間これらで使用されます。

于 2013-01-27T17:43:53.653 に答える
1

コメントによると、スレッドはでビジーでQWaitConditionあるため、シグナルを処理できません。が本当に必要な場合は、次のように、タイムアウトQWaitConditionを使用してスロットのポーリングを行うことができます。QCoreApplication::processEvents

while(true) {
    if(condition.wait(&mutex, 1000)) {
        // process condition
    } else {
        QCoreApplication::processEvents()
    }
}

ただし、これには信号の処理の遅延が含まれます(この例では1秒)。これ以外にも、SOについて同様の質問がQWaitConditionあり、代わりにシグナル/スロットを削除して使用する ことをお勧めします。

于 2013-01-27T17:20:31.553 に答える