60

Qt のドキュメントには、シグナルとスロットはdirect、 、queuedおよびであると記載されていますauto

また、スロットを所有するオブジェクトがシグナルを所有するオブジェクトとは異なるスレッドに「住んでいる」場合、そのようなシグナルを発行することはメッセージを投稿するようなものになると述べました-シグナルの発行は即座に戻り、スロットメソッドはターゲットスレッドのイベントループで呼び出されます。

残念ながら、ドキュメントには「lives」が何を意味するかは明記されておらず、例もありません。次のコードを試しました:

main.h:

class CThread1 : public QThread
{
Q_OBJECT
public:
    void run( void )
    {
        msleep( 200 );
        std::cout << "thread 1 started" << std::endl;
        MySignal();
        exec();
    }
signals:
    void MySignal( void );
};

class CThread2 : public QThread
{
Q_OBJECT
public:
    void run( void )
    {
        std::cout << "thread 2 started" << std::endl;
        exec();
    }
public slots:
    void MySlot( void )
    {
        std::cout << "slot called" << std::endl;
    }
};

main.cpp:

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    CThread1 oThread1;
    CThread2 oThread2;
    QObject::connect( & oThread1, SIGNAL( MySignal() ),
        & oThread2, SLOT( MySlot() ) );
    oThread1.start();
    oThread2.start();
    oThread1.wait();
    oThread2.wait();
    return a.exec();
}

出力は次のとおりです。

thread 2 started
thread 1 started

MySlot()呼び出されることはありません:(。私が間違っていることは何ですか?

4

3 に答える 3

48

あなたのコードにはかなりの問題があります:

  • Evan が言ったように、emit キーワードがありません
  • すべてのオブジェクトはメインスレッドに存在し、実行メソッドのコードのみが他のスレッドに存在します。つまり、MySlot スロットはメインスレッドで呼び出され、それがあなたが望むものかどうかわかりません
  • メイン イベント ループが起動されないため、スロットが呼び出されることはありません。wait() への 2 回の呼び出しは、非常に長い時間が経過するとタイムアウトするだけです (そして、それが発生する前にアプリケーションを強制終了する可能性があります)。とにかく、それらは実際にはコードでは役に立ちません。

このコードはおそらくうまくいくでしょう(私はテストしていませんが)、あなたがやりたいことをすると思います:

class MyObject : public QObject
{
    Q_OBJECT
public slots:
    void MySlot( void )
    {
        std::cout << "slot called" << std::endl;
    }
};

class CThread1 : public QThread
{
    Q_OBJECT
public:
    void run( void )
    {
        std::cout << "thread 1 started" << std::endl;
        int i = 0;
        while(1)
        {
           msleep( 200 );
           i++;
           if(i==1000)
              emit MySignal();
        }
    }
signals:
    void MySignal( void );
};

class CThread2 : public QThread
{
    Q_OBJECT
public:
    void run( void )
    {
        std::cout << "thread 2 started" << std::endl;
        exec();
    }
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    CThread1 oThread1;
    CThread2 oThread2;
    MyObject myObject;
    QObject::connect( & oThread1, SIGNAL( MySignal() ),
        & myObject, SLOT( MySlot() ) );
    oThread2.start();
    myObject.moveToThread(&oThread2)
    oThread1.start();
    return a.exec();
}

これで、MyObject はスレッド 2 に存在します (moveToThread のおかげです)。

MySignal は thread1 から送信する必要があります (それについてはよくわかりませんが、メインスレッドから送信される可能性がありますが、実際には問題ではありません)。

シグナルの発行にはイベント ループが必要ないため、スレッド 1 にはイベント ループは必要ありません。シグナルを受信するには、スレッド 2 (exec() によって起動される) にイベント ループが必要です。

MySlot はスレッド 2 で呼び出されます。

于 2009-03-12T13:49:39.707 に答える
39

Qt 4.4+ の QThread をサブクラス化しないでください

Aiua の回答は良いものですが、QThread と Qt 4.6 または 4.7 に関するいくつかの問題を指摘したいと思います。

この記事はそれを要約しています: http://blog.qt.io/blog/2010/06/17/youre-doing-it-wrong/

Qt側のドキュメントの欠如

残念ながら、この問題はドキュメントの更新がないことに起因しています。Qt 4.4 より前の QThread にはデフォルトの run() 実装がありませんでした。つまり、使用するには QThread をサブクラス化する必要がありました。

Qt 4.6 または 4.7 を使用している場合は、ほぼ確実にQThread をサブクラス化しないでください。

moveToThread を使用する

スロットをワーカー スレッドで実行するための鍵は、Aiua が指摘したように moveToThread メソッドを使用することです。

于 2011-12-02T17:24:34.250 に答える