Qthread의 맥락에서 방법을 호출합니다
-
06-07-2019 - |
문제
내 응용 프로그램에는 기본 스레드와 작업자 스레드가 있습니다 (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();
}
두 가지 방법 모두 메인 스레드 ID가 인쇄됩니다. QThread
doWork
.
또한 간단한 생산자 소비자를 구현할 생각이지만 이것이 효과가 있다면 왜 이런 식으로 그렇게하지 않는 이유가 있습니까?
해결책
문제는 수신기 (Qthread)가 기본 스레드에서 '살아 가기'하므로 기본 스레드의 이벤트 루프는 슬롯을 실행하는 것입니다.
QT의 문서에서 :
대기열 연결을 사용하면 컨트롤이 객체가 속한 스레드의 이벤트 루프로 돌아올 때 슬롯이 호출됩니다. 슬롯은 수신기 객체가있는 스레드에서 실행됩니다.
그래서 지금까지 찾은 솔루션은 스레드 런 () 내부에 객체를 만들고 대신 슬롯을 사용하는 것이 었습니다. 이렇게하면 수신기의 소유자가 스레드이고 슬롯이 스레드 컨텍스트에서 호출됩니다.
다른 팁
이 예제는 작업자 클래스를 분할하여 원하는대로 작동하도록하는 방법을 보여줍니다. 또한 슬롯에 연결할 수 있도록 작업자 인스턴스에 대한 참조 또는 포인터를 사용할 수 있도록해야합니다.
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();
}
};
간단한 프로듀서 소비자 예를 위해 Bradley T. Hughes의 블로그 항목을 살펴보십시오. 두통없이 밟는 것.
작업자는 기본 스레드에서 생성되므로 이벤트는 기본 스레드에서 처리됩니다. 작업자를 자신의 스레드로 옮겨야합니다.
Worker worker;
worker.moveToThread(&worker);
worker.start();
이제 QT는 알고 있습니다 worker
새로운 스레드에 살고 있으며 해당 이벤트 루프에서 이벤트를 줄입니다.
기능을 호출하거나 신호를 보내기 전에 작업자 스레드가 완료되는 것처럼 보입니다.