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