Qt
스레딩 및 동시성
수색…
비고
여기 및 여기 공식 문서에서 이미 언급 한 몇 가지 참고 사항 :
- 객체에 부모가있는 경우 부모와 동일한 스레드에 있어야합니다. 즉, 새 스레드로 이동할 수 없으며 부모와 객체가 다른 스레드에있을 경우 부모를 객체로 설정할 수 없습니다.
- 오브젝트가 새로운 thread로 이동하면, 그 모든 자식도 새로운 thread로 이동됩니다.
- 객체를 새 스레드에만 푸시 할 수 있습니다. 새 스레드로 끌어 올 수 없습니다. 즉, 객체가 현재 살고있는 스레드에서만
moveToThread
를 호출 할 수 있습니다.
QThread의 기본 사용법
QThread
는 플랫폼 스레드에 대한 핸들입니다. 스레드의 수명을 모니터링하고 스레드가 작업을 완료하도록 요청하여 스레드를 관리 할 수 있습니다.
대부분의 경우 클래스에서 상속하는 것은 권장되지 않습니다. 기본 run
메소드는 클래스에있는 오브젝트에 이벤트를 전달할 수있는 이벤트 루프를 시작합니다. 크로스 스레드 신호 슬롯 연결은 QMetaCallEvent
를 대상 객체로 전달하여 구현됩니다.
QObject
인스턴스는 스레드로 이동하여 타이머 이벤트 나 슬롯 / 메소드 호출과 같은 이벤트를 처리합니다.
스레드에서 작업을 수행하려면 먼저 QObject
에서 파생 된 고유 한 작업자 클래스를 만듭니다. 그런 다음 스레드로 이동하십시오. 객체는 QMetaObject::invokeMethod()
사용하여 자신의 코드를 자동으로 실행할 수 있습니다.
#include <QObject>
class MyWorker : public QObject
{
Q_OBJECT
public:
Q_SLOT void doWork() {
qDebug() << "doWork()" << QThread::currentThread();
// and do some long operation here
}
MyWorker(QObject * parent = nullptr) : QObject{parent} {}
};
class MyController : public QObject
{
Q_OBJECT
Worker worker;
QThread workerThread;
public:
MyController() {
worker.moveToThread(&workerThread);
// provide meaningful debug output
workerThread.setObjectName("workerThread");
workerThread.start();
// the thread starts the event loop and blocks waiting for events
}
~MyController() {
workerThread.quit();
workerThread.wait();
}
void operate() {
// Qt::QueuedConnection ensures that the slot is invoked in its own thread
QMetaObject::invokeMethod(&worker, "doWork", Qt::QueuedConnection);
}
};
작업자가 일시적이어야하며 작업이 완료되는 동안 만 존재해야하는 경우 QtConcurrent::run
통해 스레드 풀에서 실행을 위해 펑터 또는 스레드 안전 메소드를 제출하는 것이 가장 좋습니다.
Qt 동시 실행
뮤텍스 또는 세마포어와 같은 QThreads 및 저수준 프리미티브를 관리하는 것이 너무 복잡하다면 Qt 동시 네임 스페이스가 원하는 것입니다. 여기에는 더 높은 수준의 스레드 관리를 허용하는 클래스가 포함됩니다.
Concurrent Run을 살펴 보겠습니다. QtConcurrent::run()
은 새 스레드에서 함수를 실행할 수있게합니다. 언제 그것을 사용하고 싶습니까? 긴 작업이 있고 수동으로 스레드를 만들지 않으려는 경우
이제 코드 :
#include <qtconcurrentrun.h>
void longOperationFunction(string parameter)
{
// we are already in another thread
// long stuff here
}
void mainThreadFunction()
{
QFuture<void> f = run(longOperationFunction, "argToPass");
f.waitForFinished();
}
그래서 간단합니다 : 다른 스레드에서 다른 함수를 실행해야 할 때 QtConcurrent::run
호출하고 함수와 매개 변수를 전달하면됩니다.
QFuture
는 우리의 비동기 계산 결과를 보여줍니다. QtConcurrent::run
경우 함수 실행을 취소 할 수 없습니다.
다른 스레드에서 슬롯 호출
Qt 이벤트 루프를 사용하여 작업을 수행하고 비 Qt 사용자가 해당 이벤트 루프와 상호 작용해야 할 때 다른 스레드의 일반 호출을 처리하는 슬롯을 작성하면 다른 사용자의 작업을 단순화 할 수 있습니다.
main.cpp :
#include "OperationExecutioner.h"
#include <QCoreApplication>
#include <QThread>
int main(int argc, char** argv)
{
QCoreApplication app(argc, argv);
QThread thrd;
thrd.setObjectName("thrd");
thrd.start();
while(!thrd.isRunning())
QThread::msleep(10);
OperationExecutioner* oe = new OperationExecutioner;
oe->moveToThread(&thrd);
oe->doIt1(123,'A');
oe->deleteLater();
thrd.quit();
while(!thrd.isFinished())
QThread::msleep(10);
return 0;
}
OperationExecutioner.h :
#ifndef OPERATION_EXECUTIONER_H
#define OPERATION_EXECUTIONER_H
#include <QObject>
class OperationExecutioner : public QObject
{
Q_OBJECT
public slots:
void doIt1(int argi, char argc);
};
#endif // OPERATION_EXECUTIONER_H
OperationExecutioner.cpp :
#include "OperationExecutioner.h"
#include <QMetaObject>
#include <QThread>
#include <QDebug>
void OperationExecutioner::doIt1(int argi, char argc)
{
if (QThread::currentThread() != thread()) {
qInfo() << "Called from thread" << QThread::currentThread();
QMetaObject::invokeMethod(this, "doIt1", Qt::QueuedConnection,
Q_ARG(int,argi), Q_ARG(char,argc));
return;
}
qInfo() << "Called from thread" << QThread::currentThread()
<< "with args" << argi << argc;
}
OperationExecutioner.pro :
HEADERS += OperationExecutioner.h
SOURCES += main.cpp OperationExecutioner.cpp
QT -= gui