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

605   2  

2 ответов:

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

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

в 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.

Comments

    Ничего не найдено.