Как испустить поперечный сигнал в Qt?

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

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

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

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


person grigoryvp    schedule 12.03.2009    source источник


Ответы (3)


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

  • как сказал Эван, ключевое слово 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 (думал, что я не уверен в этом, он может быть отправлен из основного потока, на самом деле это не имеет значения).

Цикл событий в thread1 не требуется, поскольку для выдачи сигнала цикл событий не требуется. Для получения сигнала в потоке 2 требуется цикл обработки событий (запускаемый функцией exec ()).

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

person Aiua    schedule 12.03.2009
comment
есть ли способ подключить слот к сигналу до запуска потоков? Я действительно не хочу, чтобы потоки что-то испускали до того, как все будет подключено. - person grigoryvp; 12.03.2009
comment
В моем примере соединение выполняется до запуска потока, выполняющего излучение. Жду до 1000, просто для удовольствия;) - person Aiua; 12.03.2009
comment
Спасибо, moveToThread работает до запуска любого потока. конечно myThread.moveToThread (& myThread); выглядит немного странно, но работает нормально. - person grigoryvp; 13.03.2009
comment
Строго говоря, использование ключевого слова emit не должно ни на что влиять. Это # определено для пустого макроса. - person Michael Bishop; 22.03.2009
comment
Что, если сигнал испускается из потока, отличного от qt (т.е. скажем, из потока, созданного с ускорением), это проблема или это вообще возможно? Например, если у меня есть класс сетевого сервера, отличный от qt, который может вызывать обратные вызовы из своего внутреннего потока при получении сообщений, и я хочу использовать его в проекте QT и направлять эти обратные вызовы в слоты QT. - person shadow_map; 31.01.2017

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

Хотя ответ 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

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

person Will Bickford    schedule 02.12.2011
comment
Создание подклассов QThread и переопределение run() поддерживается Qt. Это даже первое предлагаемое Qt решение в этой таблице. Однако это следует использовать только тогда, когда для потока не требуется цикл обработки событий. В частности, если кому-то нужно вызвать moveToThread(this); внутри потока, как показано в связанной статье, он использует это неправильно. - person JojOatXGME; 25.06.2017
comment
Это была официальная рекомендация до выхода этой статьи: woboq.com/blog/qthread-you-were-not-doing-so-wrong.html Я реализовал потоки таким способом, и он очень легкий. Стабильно как танк. Нет moveToThread. Никаких дополнительных объектов QObject не выделяется. Вы действительно можете поместить рабочий код в функцию run () (или вызвать ее оттуда). Теперь они официально это поддерживают. - person CodeLurker; 05.06.2019

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

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

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

person kuake56    schedule 22.12.2018