Вопрос

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

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

К сожалению, в документации не указано, что означает "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() никогда не вызывается :(.Что я делаю не так?

Это было полезно?

Решение

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

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

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

MySlot будет вызван в thread2.

Другие советы

Не создавайте подкласс 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, как указал Aiua.

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top