Подтвердить что ты не робот

Как испустить сигнал кросс-нитки в Qt?

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

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

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

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

4b9b3361

Ответ 1

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

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

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

MySlot вызывается в thread2.

Ответ 2

Не подклассы 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 не выполнял реализацию по умолчанию(), что означало, что вам пришлось подклассифицировать QThread, чтобы использовать его.

Если вы используете Qt 4.6 или 4.7, вы почти наверняка не должны подклассифицировать QThread.

Использовать moveToThread

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

Ответ 3

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

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

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