Вызов методов в контексте QThread
В моем приложении есть основной поток и рабочий поток (QThread
).
Из основного потока я хотел бы вызвать метод моего рабочего потока и запустить его в контексте потока.
Я попытался использовать QMetaObject::invokeMethod
и дать ему параметр QueuedConnection
, но он не работает.
Я также пробовал испускать сигналы из основного потока (который подключен к слоту рабочего потока), но это также не удалось.
Вот фрагмент примерно того, что я пробовал:
class Worker : public QThread
{
Q_OBJECT
public:
Worker() { }
void run()
{
qDebug() << "new thread id " << QThread::currentThreadId();
exec();
}
public slots:
void doWork()
{
qDebug() << "executing thread id - " << QThread::currentThreadId();
}
};
Использование способа QMetaObject:
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qDebug() << "main thread id - " << QThread::currentThreadId();
Worker worker;
worker.start();
QMetaObject::invokeMethod(&worker, "doWork", Qt::QueuedConnection);
return a.exec();
}
Использование пути сигнала:
class Dummy : public QObject
{
Q_OBJECT
public:
Dummy() { }
public slots:
void askWork() { emit work(); }
signals:
void work();
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qDebug() << "main thread id - " << QThread::currentThreadId();
Worker worker;
worker.start();
Dummy dummy;
QObject::connect(&dummy, SIGNAL(work()), &worker, SLOT(doWork()), Qt::QueuedConnection);
QTimer::singleShot(1000, &dummy, SLOT(askWork()));
return a.exec();
}
Оба способа приводят к тому, что идентификатор основного потока печатается в QThread
doWork
.
Кроме того, я думал о внедрении простого производителя-потребителя, но если это работает, есть ли причина, почему бы не сделать это таким образом?
Ответы
Ответ 1
Проблема заключалась в том, что приемник (QThread) "живет" в основном потоке, и, таким образом, цикл событий основного потока является тем, который выполняет слот.
из Qt docs:
При подключении в очереди слот вызывается, когда элемент управления возвращается в цикл событий потока, к которому принадлежит объект. Слот выполняется в потоке, в котором живет объект приемника.
Итак, решение, которое я нашел до сих пор, состояло в том, чтобы создать объект внутри потока run() и вместо этого использовать его слоты. Таким образом, владелец получателя является потоком, а затем слот вызывается в контексте потоков.
Ответ 2
Для простого примера производителя-потребителя ознакомьтесь с записью в блоге от Bradley T. Hughes Наступать без головной боли.
Ответ 3
В этом примере показано, как вы можете разделить класс Worker, чтобы он работал так, как вы хотите. Вам также необходимо предоставить ссылку или указатель на экземпляр Worker, чтобы иметь возможность подключиться к слоту.
class Worker : public QObject
{
Q_OBJECT
public:
Worker() { }
public slots:
void doWork()
{
qDebug() << "executing thread id - " << QThread::currentThreadId();
}
};
class WorkerThread : public QThread
{
Q_OBJECT
public:
void run()
{
qDebug() << "new thread id " << QThread::currentThreadId();
Worker worker;
exec();
}
};
Ответ 4
Рабочий создается в основном потоке, и поэтому его события выполняются в основном потоке. Вы должны переместить Работника в его собственный поток:
Worker worker;
worker.moveToThread(&worker);
worker.start();
Теперь Qt знает worker
живет в новом потоке и будет помещать в очередь события в этом цикле событий.
Ответ 5
Похоже, ваш рабочий поток завершается, прежде чем вы сможете даже вызвать любую функцию или отправить на нее сигнал.