Как излучать межпоточный сигнал в Qt? - PullRequest
58 голосов
/ 12 марта 2009

Документация Qt гласит, что сигналы и слоты могут быть direct, queued и auto.

Также указывалось, что если объект, которому принадлежит слот, «живет» в потоке, отличном от объекта, которому принадлежит сигнал, испускание такого сигнала будет похоже на отправку сообщения - сигнал emit будет возвращен немедленно, и метод слота будет вызван в цикле событий целевого потока ,

К сожалению, в документации не указано, что означает «жизнь», и примеры отсутствуют. Я пробовал следующий код:

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() никогда не вызывается :(. Что я делаю не так?

Ответы [ 3 ]

46 голосов
/ 12 марта 2009

С вашим кодом довольно много проблем:

  • как сказал Эван, ключевое слово emit отсутствует
  • все ваши объекты живут в основном потоке, только код в методах выполнения живет в других потоках, что означает, что слот MySlot будет вызываться в основном потоке, и я не уверен, что вы этого хотите
  • ваш слот никогда не будет вызван, так как главный цикл обработки событий никогда не будет запущен: ваши два вызова wait () прекратят работу только через очень долгое время (и вы, вероятно, убьете свое приложение до того, как это произойдет), и я не буду Не думаю, что это то, что вы хотите, в любом случае они действительно бесполезны в вашем коде.

Этот код, скорее всего, будет работать (хотя я его не проверял), и я думаю, что он делает то, что вы хотите:

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 будет жить в thread2 (благодаря moveToThread).

MySignal должен быть отправлен из потока 1 (хотя я не уверен в этом, он может быть отправлен из основного потока, это не имеет значения).

В потоке 1 не требуется цикл обработки событий, поскольку для генерации сигнала не требуется цикл обработки событий. Цикл событий необходим в thread2 (запрограммирован exec ()) для получения сигнала.

MySlot будет вызываться в thread2.

36 голосов
/ 02 декабря 2011

Не создавать подкласс QThread для Qt 4.4 +

Хотя ответ Аиуа хороший, я хочу указать на некоторые проблемы с 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

Ключом к получению слотов для выполнения в рабочем потоке является использование метода moveToThread, как указал Аиуа.

0 голосов
/ 22 декабря 2018

вы должны подать сигнал, чтобы запустить функцию потока как

emit operateCut(examId,examName_examTemplate[examName].studentIdRec,examName_examTemplate[examName].choiceRecA,examName_examTemplate[examName].choiceRecB,examName_examTemplate[examName].objectRecA,examName_examTemplate[examName].objectRecB);

Вы можете добавить более одного аргумента в этот сигнал

...