이 페이지에서

Qt TaskTree C++ Classes

범용 TaskTree 라이브러리가 포함되어 있습니다. 더 보기...

이 모듈은 개발 중이며 변경될 수 있습니다.

이 모듈은 Qt 6.11에 도입되었습니다.

네임스페이스

QtTaskTree

TaskTree 모듈의 모든 클래스와 전역 함수를 둘러쌉니다.

클래스

QtTaskTree::Do

For 및 When 구문과 함께 사용되는 본문 요소입니다.

QtTaskTree::Else

조건 표현식에 사용되는 "else" 요소

QtTaskTree::ElseIf

조건 표현식에 사용되는 "else if" 요소

QtTaskTree::ExecutableItem

실행 가능한 작업 항목의 베이스 클래스

QtTaskTree::ExecutionMode

실행 모드를 설명하는 그룹 요소

QtTaskTree::For

for 루프 요소

QtTaskTree::Forever

하위 작업의 무한 루프

QtTaskTree::ForeverIterator

For 요소 내부에서 사용되는 무한 반복자

QtTaskTree::Group

비동기 작업의 중첩된 트리를 실행하고 처리하는 방법을 설명하는 선언적 레시피를 구성하기 위한 기본 요소를 나타냅니다.

QtTaskTree::GroupItem

모든 그룹의 일부가 될 수 있는 기본 요소를 나타냅니다.

QtTaskTree::If

조건 표현식에 사용되는 "if" 요소

QtTaskTree::Iterator

For 요소 내부에서 이터레이터로 사용되는 베이스 클래스

QtTaskTree::ListIterator

For 요소 내에서 사용할 목록 이터레이터

QtTaskTree::ObjectSignal

QObject 서브클래스와 그 신호를 설명하는 구조체

QtTaskTree::ParallelLimit

사용자 지정 제한이 있는 병렬 실행 모드

QtTaskTree::QBarrier

필요에 따라 완료되는 비동기 작업

QtTaskTree::QCustomTask

사용자 정의 작업 항목을 선언하고 설정 및 완료 핸들러를 정의하는 데 사용되는 클래스 템플릿

QtTaskTree::QDefaultTaskAdapter

QCustomTask에서 사용되는 기본 작업 어댑터를 제공하는 클래스 템플릿

QtTaskTree::QMappedTaskTreeRunner

주어진 키 유형을 가진 매핑된 작업 트리 실행 컨트롤러

QtTaskTree::QNetworkReplyWrapper

QNetworkReply와 QNetworkAccessManager를 둘러싼 래퍼

QtTaskTree::QParallelTaskTreeRunner

병렬 작업 트리 실행 컨트롤러

QtTaskTree::QProcessTaskDeleter

QProcessTask에서 사용하는 QProcess용 사용자 정의 삭제자

QtTaskTree::QSequentialTaskTreeRunner

순차적 작업 트리 실행 컨트롤러

QtTaskTree::QSingleTaskTreeRunner

단일 작업 트리 실행 컨트롤러

QtTaskTree::QStartedBarrier

주어진 제한으로 시작된 QBarrier

QtTaskTree::QSyncTask

다른 작업 사이에 사용자 정의 핸들러를 동기적으로 실행합니다.

QtTaskTree::QTaskInterface

사용자 지정 태스크의 인터페이스를 조정할 때 사용되는 도우미 클래스

QtTaskTree::QTaskTree

선언적 방식으로 정의된 비동기 태스크 트리를 실행합니다.

QtTaskTree::QTcpSocketWrapper

QTcpSocket을 둘러싼 래퍼

QtTaskTree::QThreadFunction

QtConcurrent::run()을 통해 별도의 스레드에서 함수 실행을 제어하는 클래스 템플릿.

QtTaskTree::QThreadFunctionBase

QThreadFunction 클래스 템플릿의 베이스 클래스

QtTaskTree::RepeatIterator

For 요소 내에서 사용되는 반복 이터레이터

QtTaskTree::Storage

실행 중인 작업 트리에서 사용자 정의 데이터 교환을 위한 클래스 템플릿

QtTaskTree::Then

조건 표현식에 사용되는 "then" 요소

QtTaskTree::UntilIterator

For 요소 내부에서 사용되는 조건부 반복자

QtTaskTree::When

배리어 전진까지 바디의 실행을 지연시키는 요소

상세 설명

태스크트리 라이브러리를 사용하여 실행할 비동기 작업을 설명하는 레시피를 구성하고, QTaskTree 내에서 이 레시피를 사용하여 실행합니다.

레시피는 생성 및 실행할 작업 유형에 대한 선언적 설명입니다: QProcess, QNetworkReplyWrapper, 또는 QThreadFunction<ReturnType> 등, 또는 순차적으로 실행할지 병렬로 실행할지에 대한 선언적 설명입니다. 레시피 내에서 이전 작업이 성공적으로 완료되었는지 또는 오류로 완료되었는지에 따라 다른 연속 경로를 정의할 수 있습니다. 또한 Group 요소에 작업을 중첩할 수 있으며, 각 Group 은 자체 실행 모드나 워크플로 정책에 따라 작업을 실행할 수 있습니다. 레시피는 작업 트리 구조를 형성합니다.

비동기 작업

비동기 작업은 시작되었다가 나중에 성공 또는 오류로 완료될 수 있는 모든 작업입니다. 나중에란 작업을 시작한 후 제어가 실행 중인 이벤트 루프로 돌아가는 것을 의미합니다. 작업이 완료될 때까지 호출자 스레드를 차단하지 않습니다. 작업 트리를 사용하려면 이벤트 루프가 회전해야 합니다.

비동기 태스크의 예시:

레시피 & 태스크 트리

레시피와 태스크 트리가 무엇인지 기억하기 위해 카트리지와 플레이어에 비유해 보겠습니다. 레시피를 작성할 때는 카트리지를 만드는 것과 같아서 나중에 카트리지를 플레이어(태스크 트리) 안에 넣고 시작했을 때 플레이어가 무엇을 해야 하는지에 대한 자세한 설명을 준비하면 됩니다. 레시피 자체는 태스크 트리에 레시피가 전달되고 태스크 트리가 시작되었을 때 태스크 트리가 수행해야 할 작업에 대한 선언적 설명일 뿐입니다. 레시피 자체는 태스크 트리 없이는 자체적으로 아무것도 수행하지 않으며, 플레이어가 없는 카트리지와 같습니다.

다음은 레시피와 태스크 트리의 책임에 대한 간략한 요약입니다.

레시피(카트리지)에 대해 설명합니다:

  • 실행 중인 작업 트리에서 동적으로 생성할 작업(QCustomTask를 통해)
  • 어떤 순서로
  • 실행 중인 작업 트리에서 동적으로 생성할 데이터 구조( Storage 를 통해)
  • 시작하기 전에 각 작업을 설정하는 방법
  • 작업이 완료되면 데이터를 수집하는 방법
  • 실행 모드(작업은 순차적으로 또는 병렬로 실행되어야 함)
  • 워크플로 정책

작업 트리(플레이어):

  • 레시피를 읽고 작업과 데이터 구조를 자동으로 생성합니다.
  • 생성된 작업과 데이터 구조의 수명을 관리합니다.
  • 연속 작업 실행
  • 완료된 작업의 결과 및 워크플로 정책에 따라 다른 경로 선택
  • 기본 진행 정보 제공

사용자 지정 작업

레시피는 작업 트리가 시작될 때 어떤 작업을 만들어야 하는지에 대한 작업 트리에 대한 설명이므로 레시피 내에서 이러한 작업을 직접 만들 수는 없습니다. 대신 나중에 이러한 작업을 만들어서 시작하도록 작업 트리에 지시하는 선언적 방법이 필요합니다. 예를 들어 작업 트리가 QProcess 를 만들고 시작하도록 하려면 레시피 안에 QProcessTask 요소를 배치하여 설명합니다. QProcessTaskQCustomTask<QProcess>의 별칭입니다. 각 작업 유형은 레시피 내에서 사용할 수 있도록 해당 QCustomTask<Type>을 제공해야 합니다.

다음 표는 레시피 안에 배치할 수 있는 몇 가지 기본 제공 사용자 지정 작업을 보여줍니다:

사용자 지정 작업(레시피에 사용됨)태스크 클래스(실행 중인 태스크 트리에 의해 생성됨)간단한 설명
QProcessTaskQProcess프로세스를 시작합니다.
QThreadFunctionTask<ReturnType>QThreadFunction<ReturnType>비동기 작업을 시작하고 별도의 스레드에서 실행합니다.
QTaskTreeTaskQTaskTree중첩된 작업 트리를 시작합니다.
QNetworkReplyWrapperTaskQNetworkReplyWrapper네트워크 다운로드를 시작합니다.
QTcpSocketWrapperTaskQTcpSocketWrapperTCP 연결을 시작합니다.

특정 작업을 레시피 내에서 사용하도록 조정하는 방법에 대한 자세한 내용은 QTaskInterfaceTask Adapters 을 참조하세요.

예제 레시피

QTaskTree 에는 레시피라고 하는 최상위 Group 요소가 있으며, 여기에는 QProcessTask, QNetworkReplyWrapperTask, 또는 QThreadFunctionTask<ReturnType>와 같은 다양한 유형의 작업을 얼마든지 포함할 수 있습니다:

const Group recipe {
    QProcessTask(...),
    QNetworkReplyWrapperTask(...),
    QThreadFunctionTask<int>(...)
};

QTaskTree *taskTree = new QTaskTree(recipe);
connect(taskTree, &QTaskTree::done, ...);  // finish handler
taskTree->start();

위의 레시피는 QProcessTask, QNetworkReplyWrapperTask, QThreadFunctionTask<int> 유형의 작업을 포함하는 Group 유형의 최상위 요소로 구성됩니다. taskTree->start() 이 호출되면 QProcess 부터 시작하여 태스크가 생성되고 체인으로 실행됩니다. QProcess 이 성공적으로 완료되면 QNetworkReplyWrapper 작업이 시작됩니다. 마지막으로 네트워크 작업이 성공적으로 완료되면 QThreadFunction<int> 작업이 시작됩니다.

마지막 실행 중인 작업이 성공적으로 완료되면 작업 트리가 성공적으로 실행된 것으로 간주되고 QTaskTree::done() 신호가 DoneWith::Success 과 함께 전송됩니다. 작업이 오류로 완료되면 작업 트리의 실행이 중지되고 나머지 작업은 건너뜁니다. 작업 트리가 오류로 완료되면 QTaskTree::done() 신호가 DoneWith::Error 과 함께 전송됩니다.

그룹

Group 의 부모는 이를 단일 작업으로 간주합니다. 다른 작업과 마찬가지로 그룹은 시작될 수 있으며 성공 또는 오류로 완료될 수 있습니다. Group 요소를 중첩하여 트리 구조를 만들 수 있습니다:

const Group recipe {
    Group {
        parallel,
        QProcessTask(...),
        QThreadFunctionTask<int>(...)
    },
    QNetworkReplyWrapperTask(...)
};

위의 예는 최상위 요소에 QProcessTaskQThreadFunctionTask<int>를 포함하는 하위 그룹이 있다는 점에서 첫 번째 예와 다릅니다. 하위 그룹은 루트에 있는 QNetworkReplyWrapperTask 요소의 형제 요소입니다. 하위 그룹에는 parallel 요소가 추가로 포함되어 있어 Group 에 작업을 병렬로 실행하도록 지시합니다.

따라서 QTaskTree 에서 위의 레시피를 시작하면 QProcessQThreadFunction<int> 가 즉시 시작되어 병렬로 실행됩니다. 루트 그룹에는 parallel 요소가 포함되어 있지 않으므로 직접 하위 작업이 순서대로 실행됩니다. 따라서 전체 하위 그룹이 완료되면 QNetworkReplyWrapper 이 시작됩니다. 그룹은 모든 작업이 완료되면 완료된 것으로 간주됩니다. 작업이 완료되는 순서는 중요하지 않습니다.

따라서 어떤 작업이 더 오래 지속되는지(QProcess 또는 QThreadFunction<int>)에 따라 다음과 같은 시나리오가 발생할 수 있습니다:

시나리오 1시나리오 2
루트 그룹 시작루트 그룹 시작
하위 그룹 시작하위 그룹 시작
QProcess 시작QProcess starts
QThreadFunction<int> 시작QThreadFunction<int> 시작
......
QProcess finishesQThreadFunction<int> 완료
......
QThreadFunction<int> 완료QProcess finishes
하위 그룹 완료하위 그룹 완료
QNetworkReplyWrapper 시작QNetworkReplyWrapper 시작
......
QNetworkReplyWrapper 종료QNetworkReplyWrapper 완료
루트 그룹 완료루트 그룹 완료

시나리오 간의 차이점은 굵은 글씨로 표시되어 있습니다. 점 3개는 이전 이벤트와 다음 이벤트 사이에 지정되지 않은 시간이 경과했음을 의미합니다(작업은 계속 실행됨). 이벤트 사이에 점이 없으면 이벤트가 동시에 발생한다는 의미입니다.

제시된 시나리오에서는 모든 작업이 성공적으로 실행된다고 가정합니다. 실행 중에 작업이 실패하면 작업 트리가 오류와 함께 완료됩니다. 특히 QThreadFunction<int>가 실행 중인 상태에서 QProcess 가 오류로 완료되면 QThreadFunction<int>는 자동으로 취소되고 하위 그룹은 오류로 완료되며 QNetworkReplyWrapper 는 건너뛰고 트리는 오류로 완료됩니다.

작업 핸들러

Task 핸들러를 사용하여 실행할 작업을 설정하고 작업이 성공 또는 오류로 완료될 때 작업의 출력 데이터를 읽을 수 있도록 설정할 수 있습니다.

태스크의 시작 핸들러

작업 개체가 만들어지고 시작되기 전에 작업 트리는 선택적으로 사용자가 제공한 설정 핸들러를 호출합니다. 설정 핸들러는 항상 연결된 작업 클래스 개체에 대한 참조를 가져와야 합니다:

const auto onSetup = [](QProcess &process) {
    process.setProgram("sleep");
    process.setArguments({"3"});
};
const Group root {
    QProcessTask(onSetup)
};

설정 핸들러에서 전달된 QProcess 을 수정하여 작업 트리가 구성에 따라 프로세스를 시작할 수 있도록 할 수 있습니다. 설정 핸들러에서 process.start(); 을 호출해서는 안 됩니다. 작업 트리가 필요할 때 호출하기 때문입니다. 설정 핸들러는 선택 사항입니다. 사용하는 경우에는 작업 생성자의 첫 번째 인수가 되어야 합니다.

선택적으로 설정 핸들러는 SetupResult 를 반환할 수 있습니다. 반환된 SetupResult 은 지정된 작업의 추가 시작 동작에 영향을 미칩니다. 가능한 값은 다음과 같습니다:

SetupResult간단한 설명
Continue작업이 정상적으로 시작됩니다. 설정 처리기가 SetupResult (즉, 반환 유형이 void)를 반환하지 않을 때의 기본 동작입니다.
StopWithSuccess작업이 시작되지 않고 부모에게 성공을 보고합니다.
StopWithError작업이 시작되지 않고 부모에게 오류를 보고합니다.

이는 조건이 충족될 때만 작업을 실행하고 이전에 시작된 작업이 완료될 때까지 이 조건을 평가하는 데 필요한 데이터를 알 수 없는 경우에 유용합니다. 이러한 방식으로 설정 핸들러는 해당 작업을 정상적으로 시작할지 아니면 건너뛰고 성공 또는 오류를 보고할지 여부를 동적으로 결정합니다. 작업 간 데이터 교환에 대한 자세한 내용은 Storage 을 참조하세요.

작업 완료 핸들러

실행 중인 작업이 완료되면 작업 트리는 선택적으로 제공된 완료 핸들러를 호출합니다. 처리기는 연결된 작업 클래스 개체에 대한 const 참조를 가져와야 합니다:

const auto onSetup = [](QProcess &process) { process.setProgram("sleep"); process.setArguments({"3"}); };const auto onDone = [](const QProcess &process, DoneWith 결과) { if (result== DoneWith::Success)        qDebug() << "Success" << process.cleanedStdOut();
   else        qDebug() << "Failure" << process.cleanedStdErr();
};const Group root { QProcessTask(onSetup, onDone) };

완료 핸들러는 QProcess 에서 출력 데이터를 수집하여 추가 처리를 위해 저장하거나 추가 작업을 수행할 수 있습니다.

참고: 작업 설정 핸들러가 StopWithSuccess 또는 StopWithError 을 반환하면 done 핸들러는 호출되지 않습니다.

그룹 핸들러

작업 처리기와 마찬가지로 그룹 처리기를 사용하면 실행할 그룹을 설정하고 전체 그룹이 성공 또는 오류로 완료될 때 더 많은 작업을 적용할 수 있습니다.

그룹의 시작 핸들러

작업 트리는 하위 작업을 시작하기 전에 그룹 시작 핸들러를 호출합니다. 그룹 핸들러는 인수를 받지 않습니다:

const auto onSetup = [] { {    qDebug() << "Entering the group";
};const Group root { onGroupSetup(onSetup), QProcessTask(...) };

그룹 설정 핸들러는 선택 사항입니다. 그룹 설정 핸들러를 정의하려면 그룹에 onGroupSetup() 요소를 추가합니다. onGroupSetup ()의 인수는 사용자 핸들러입니다. 그룹에 onGroupSetup() 요소를 두 개 이상 추가하면 런타임에 오류 메시지를 포함하는 어서트가 트리거됩니다.

작업의 시작 핸들러와 마찬가지로 그룹 시작 핸들러는 SetupResult 을 반환할 수 있습니다. 반환된 SetupResult 값은 전체 그룹의 시작 동작에 영향을 줍니다. 그룹 시작 처리기를 지정하지 않거나 반환 유형이 무효인 경우 기본 그룹의 동작은 Continue 이므로 모든 작업이 정상적으로 시작됩니다. 그렇지 않으면 시작 처리기가 StopWithSuccess 또는 StopWithError 을 반환하면 작업이 시작되지 않고(건너뛰어짐) 반환된 값에 따라 그룹 자체에서 각각 성공 또는 오류를 보고합니다.

const Group root {
    onGroupSetup([] { qDebug() << "Root setup"; }),
    Group {
        onGroupSetup([] { qDebug() << "Group 1 setup"; return SetupResult::Continue; }),
        QProcessTask(...) // Process 1
    },
    Group {
        onGroupSetup([] { qDebug() << "Group 2 setup"; return SetupResult::StopWithSuccess; }),
        QProcessTask(...) // Process 2
    },
    Group {
        onGroupSetup([] { qDebug() << "Group 3 setup"; return SetupResult::StopWithError; }),
        QProcessTask(...) // Process 3
    },
    QProcessTask(...) // Process 4
};

위의 예에서는 루트 그룹의 모든 하위 그룹이 설정 핸들러를 정의합니다. 다음 시나리오에서는 시작된 모든 프로세스가 성공적으로 완료된다고 가정합니다:

시나리오설명
루트 그룹 시작SetupResult를 반환하지 않으므로 해당 작업이 실행됩니다.
그룹 1 시작Continue를 반환하므로 해당 작업이 실행됩니다.
프로세스 1 시작
......
프로세스 1 완료(성공)
그룹 1 완료(성공)
그룹 2 시작StopWithSuccess를 반환하므로 프로세스 2가 건너뛰고 그룹 2가 성공을 보고합니다.
그룹 2 완료(성공)
그룹 3 시작StopWithError를 반환하므로 프로세스 3이 건너뛰고 그룹 3이 오류를 보고합니다.
그룹 3이 완료됨(오류)
루트 그룹이 완료됨(오류)루트 그룹의 직접 자식인 그룹 3이 오류로 완료되었으므로 루트 그룹은 실행을 중지하고 아직 시작되지 않은 프로세스 4를 건너뛰고 오류를 보고합니다.

그룹의 완료 핸들러

Group 의 완료 핸들러는 해당 작업의 실행 성공 또는 실패 후에 실행됩니다. 그룹이 보고하는 최종 값은 Workflow Policy 에 따라 달라집니다. 처리기는 다른 필요한 작업을 적용할 수 있습니다. done 핸들러는 그룹의 onGroupDone() 요소 안에 정의됩니다. 선택 사항인 DoneWith 인수를 받아 실행 성공 또는 실패를 나타낼 수 있습니다:

const Group root { onGroupSetup([] { qDebug()<< "Root setup"; }), QProcessTask(...),onGroupDone([](DoneWith result) { if (result== DoneWith::Success)            qDebug() << "Root finished with success";
       else            qDebug() << "Root finished with an error";
    }) };

그룹 완료 핸들러는 선택 사항입니다. 그룹에 onGroupDone()를 두 개 이상 추가하면 런타임에 오류 메시지를 포함하는 어설션이 트리거됩니다.

참고: 그룹 설정 핸들러가 StopWithSuccess 또는 StopWithError 을 반환하더라도 그룹의 완료 핸들러가 호출됩니다. 이 동작은 작업 완료 핸들러의 동작과 다르며 향후 변경될 수 있습니다.

기타 그룹 요소

그룹에는 execution mode 또는 workflow policy 과 같이 처리 흐름을 설명하는 다른 요소가 포함될 수 있으며, 그룹 실행 중에 수집된 사용자 지정 공통 데이터를 수집하고 공유하는 스토리지 요소도 포함될 수 있습니다.

실행 모드

그룹의 실행 모드 요소는 그룹의 직접 하위 작업이 시작되는 방법을 지정합니다. 가장 일반적인 실행 모드는 sequentialparallel 입니다. ParallelLimit 요소를 사용하여 병렬로 실행되는 작업의 제한을 지정할 수도 있습니다.

모든 실행 모드에서 그룹은 표시되는 순서대로 작업을 시작합니다.

그룹의 하위 그룹도 그룹인 경우 하위 그룹은 자체 실행 모드에 따라 작업을 실행합니다.

워크플로 정책

Group 의 워크플로 정책 요소는 직접 자식의 작업이 완료될 때 그룹이 어떻게 동작해야 하는지를 지정합니다. 사용 가능한 정책에 대한 자세한 설명은 WorkflowPolicy 을 참조하세요.

그룹의 하위 그룹도 그룹인 경우 하위 그룹은 자체 워크플로 정책에 따라 작업을 실행합니다.

스토리지

Storage 요소를 사용하여 작업 간에 정보를 교환합니다. 특히 순차 실행 모드에서는 작업이 시작되기 전에 이미 완료된 다른 작업의 데이터가 필요할 때 유용합니다. 예를 들어 소스에서 데이터를 읽고 대상에 쓰는 방식으로 데이터를 복사하는 작업 트리는 다음과 같이 보일 수 있습니다:

정적 QByteArray load(const QString &fileName) { ... }static void save(const QString &파일명, const QByteArray &array) { ... }static Group copyRecipe(const QString &소스, const QString &대상) { 구조체 CopyStorage { // [1] 커스텀 인터 태스크 구조체       QByteArray content; // [2] 커스텀 태스크간 데이터}; // [3] 태스크 트리로 관리 가능한 커스텀 태스크간 구조체의 인스턴스 const  Storage<CopyStorage> storage; const auto onLoaderSetup = [source](QThreadFunction<QByteArray> &async) { async.setThreadFunctionData(&load, source); }; // [4] 런타임: 태스크 트리가 핸들러 호출 전 [7]에서 인스턴스를 활성화합니다 const auto onLoaderDone = [storage](const  QThreadFunction<QByteArray> &async) {  storage->content = async.result(); // [5] 로더가 결과를 스토리지에 저장}; // [4] 런타임: 태스크 트리가 핸들러 호출 전 [7]에서 인스턴스를 활성화합니다 const auto onSaverSetup = [storage, destination](QThreadFunction<void> &async) { const QByteArray content =  storage->content; // [6] 세이버는 스토리지에서 데이터를 가져옵니다async.setThreadFunctionData(&save, destination, content); }; const auto onSaverDone = [](const  QThreadFunction<void> &async) {        qDebug() << "Save done successfully";
    }; const Group root { // [7] 런타임: 작업 트리는 root가스토리지에  입력되면 CopyStorage의 인스턴스를 생성하고, QThreadFunctionTask<QByteArray>(onLoaderSetup, onLoaderDone, CallDoneFlag::OnSuccess),QThreadFunctionTask<void>(onSaverSetup, onSaverDone, CallDoneFlag::OnSuccess) }; return root; }...const QString source = ...;const QString destination = ...;QTaskTree taskTree(copyRecipe(source, destination)); connect(&taskTree, &QTaskTree::done, &taskTree, [](DoneWith result) { if (result== DoneWith::Success)        qDebug() << "The copying finished successfully.";
}); tasktree.start();

위의 예에서 태스크 간 데이터는 CopyStorage 사용자 정의 구조체[1]로 묶인 QByteArray 콘텐츠 변수[2]로 구성됩니다. 로더가 성공적으로 완료되면 CopyStorage::content 변수[5]에 데이터를 저장합니다. 그런 다음 세이버는 이 변수를 사용하여 저장 작업을 구성합니다[6].

작업 트리가 CopyStorage 구조체를 관리할 수 있도록 Storage<CopyStorage>의 인스턴스가 생성됩니다[3]. 이 개체의 복사본이 그룹의 하위 항목으로 삽입되면[7], 작업 트리가 이 그룹에 들어갈 때 CopyStorage 구조체의 인스턴스가 동적으로 생성됩니다. 작업 트리가 이 그룹을 벗어나면 CopyStorage 구조체의 기존 인스턴스는 더 이상 필요하지 않으므로 소멸됩니다.

공통 Storage<CopyStorage> 인스턴스의 복사본을 보유한 여러 작업 트리가 동시에 실행되는 경우(작업 트리가 다른 스레드에서 실행되는 경우 포함), 각 작업 트리에는 자체 CopyStorage 구조체의 복사본이 포함됩니다.

스토리지 객체가 있는 그룹의 모든 핸들러에서 CopyStorage 에 액세스할 수 있습니다. 여기에는 저장소 개체가 있는 그룹의 모든 하위 작업의 모든 핸들러가 포함됩니다. 처리기에서 사용자 지정 구조에 액세스하려면 Storage<CopyStorage> 객체의 복사본을 처리기에 전달하세요(예: 람다 캡처)[4].

작업 트리가 저장소를 포함하는 하위 트리에서 처리기를 호출하면[7], 작업 트리는 Storage<CopyStorage> 개체 내부에 있는 자체 CopyStorage 인스턴스를 활성화합니다. 따라서 CopyStorage 구조체는 핸들러 본문 내에서만 액세스할 수 있습니다. Storage <CopyStorage> 내에서 현재 활성화된 CopyStorage 에 액세스하려면 Storage::operator->(), Storage::operator*() 또는 Storage::activeStorage() 메서드를 사용합니다.

다음 목록은 작업 트리에 저장소 개체를 사용하는 방법을 요약한 것입니다:

  1. 사용자 지정 데이터 [1], [2]로 사용자 지정 구조 MyStorage 정의하기
  2. Storage<MyStorage> 스토리지의 인스턴스 생성 [3]
  3. Storage<MyStorage> 인스턴스를 핸들러에 전달합니다 [4].
  4. 핸들러에서 MyStorage 인스턴스에 액세스 [5], [6]
  5. Storage<MyStorage> 인스턴스를 그룹에 삽입합니다 [7].

QTaskTree 클래스

QTaskTreeGroup 루트 요소에 설명된 레시피에 따라 비동기 작업의 트리 구조를 실행합니다.

QTaskTree 도 비동기 작업이므로 다른 QTaskTree 의 일부가 될 수 있습니다. 중첩된 QTaskTree 을 다른 QTaskTree 안에 배치하려면 QTaskTreeTask 요소를 다른 Group 요소에 삽입합니다.

QTaskTree 실행 중일 때 완료된 작업의 진행률을 보고합니다. 작업이 완료되거나 건너뛰거나 취소되면 진행률 값이 증가합니다. QTaskTree 작업이 완료되고 QTaskTree::done() 신호가 전송되면 현재 진행률 값은 최대 진행률 값과 같습니다. 최대 진행률은 트리에 있는 비동기 작업의 총 개수와 같습니다. 중첩된 QTaskTree 은 하나의 작업으로 계산되며, 그 하위 작업은 최상위 트리에서 계산되지 않습니다. 그룹 자체는 작업으로 계산되지 않지만 그 작업은 계산됩니다. QSyncTask 작업은 비동기식이 아니므로 작업으로 계산되지 않습니다.

실행 중인 트리에 대한 추가 초기 데이터를 설정하려면 스토리지 설정 핸들러를 설치하여 트리를 만들 때 트리의 스토리지 인스턴스를 수정하세요:

Storage<CopyStorage> storage;
const Group root = ...; // storage placed inside root's group and inside handlers
QTaskTree taskTree(root);
auto initStorage = [](CopyStorage &storage) {
    storage.content = "initial content";
};
taskTree.onStorageSetup(storage, initStorage);
taskTree.start();

실행 중인 작업 트리가 CopyStorage 인스턴스를 만들 때 트리 내의 처리기가 호출되기 전에 작업 트리는 initStorage 처리기를 호출하여 이 특정 실행에 고유한 taskTree 스토리지의 초기 데이터를 설정할 수 있도록 합니다.

마찬가지로, 실행 중인 트리에서 일부 추가 결과 데이터를 수집하려면 트리의 스토리지 인스턴스가 곧 소멸될 때 트리의 스토리지 인스턴스에서 데이터를 읽습니다. 이렇게 하려면 스토리지 완료 핸들러를 설치하세요:

Storage<CopyStorage> storage;const Group root = ...; // root의 그룹 내부와 핸들러 내부에 저장소 배치QTaskTree taskTree(root);auto collectStorage = [](const CopyStorage &storage) {    qDebug() << "final content" << storage.content;
}; taskTree.onStorageDone(storage, collectStorage); taskTree.start();

실행 중인 작업 트리가 CopyStorage 인스턴스를 삭제하려고 할 때, 작업 트리는 collectStorage 핸들러를 호출하여 이 특정 taskTree 실행에 고유한 스토리지에서 최종 데이터를 읽을 수 있도록 합니다.

태스크 어댑터

새로운 태스크 유형을 레시피의 일부로 허용하는 것은 매우 쉽습니다. QCustomTask 템플릿에 새 태스크 별칭을 정의하고 Task 유형을 첫 번째 템플릿 인수로 전달하기만 하면 됩니다:

class Worker : public QObject
{
public:
    void start() { ... }

signals:
    void done(bool result);
};

using WorkerTask = QCustomTask<Worker>;

다음 조건이 충족되면 이 방법이 작동합니다:

  1. 작업이 QObject 에서 파생됩니다.
  2. 작업에 작업을 시작하는 공개 start() 메서드가 있습니다.
  3. 작업이 완료되면 완료(bool) 또는 완료(DoneResult) 신호를 보냅니다.

작업이 이러한 조건을 충족하지 않는 경우에도 사용자 지정 어댑터와 함께 두 번째 템플릿 인수를 제공하여 TaskTree 프레임워크에서 작동하도록 작업을 조정할 수 있습니다. QTimer 을 TaskTree와 함께 작동하도록 조정한다고 가정해 보겠습니다. Adapter 는 다음과 같이 보일 수 있습니다:

class TimerAdapter
{
public:
    void operator()(QTimer *task, QTaskInterface *iface) {
        task->setSingleShot(true);
        QObject::connect(task, &QTimer::timeout, iface, [iface] {
            iface->reportDone(DoneResult::Success);
        });
        task->start();
    }
};

using TimerTask = QCustomTask<QTimer, TimerAdapter>;

이제 다음과 같이 레시피에서 TimerTask 을 사용할 수 있습니다:

const auto onSetup = [](QTimer &task) { task.setInterval(2000); };const auto onDone = [](const QTimer &task) {    qDebug() << "Timer triggered after" << task.interval() << "ms.";
};const Group recipe { TimerTask(onSetup, onDone) };

참고: 실행 중인 작업을 구현하는 클래스에는 기본 생성자가 있어야 하며, 이 클래스의 객체는 자유롭게 파괴할 수 있어야 합니다. 실행 중인 작업이 완료될 때까지 기다리지 않고 실행 중인 작업을 소멸할 수 있어야 합니다(즉, 실행 중인 작업의 안전한 논-블록킹 소멸자). 차단 소멸자가 있는 태스크를 비차단 소멸하려면 QCustomTask (세 번째 템플릿 인수)의 Deleter 템플릿 매개변수(선택 사항)를 사용하는 것을 고려하세요.

태스크 트리 주자

태스크 트리 러너는 주어진 레시피를 실행하는 데 사용되는 기본 QTaskTree 의 수명을 관리합니다.

다음 표에는 다양한 태스크 트리 러너 간의 차이점이 요약되어 있습니다:

클래스 이름설명
QSingleTaskTreeRunner단일 태스크 트리 실행을 관리합니다. QSingleTaskTreeRunner::start () 메서드는 전달된 레시피를 무조건 시작하여 실행 중인 모든 태스크 트리를 재설정합니다. 한 번에 하나의 태스크 트리만 실행할 수 있습니다.
QSequentialTaskTreeRunner순차적인 작업 트리 실행을 관리합니다. QSequentialTaskTreeRunner::enqueue () 메서드는 태스크 트리 실행기가 유휴 상태인 경우 전달된 레시피를 시작합니다. 그렇지 않으면 레시피가 큐에 대기합니다. 현재 작업이 완료되면 러너는 큐에 대기 중인 레시피를 순차적으로 실행합니다. 한 번에 하나의 작업 트리만 실행할 수 있습니다.
QParallelTaskTreeRunner병렬 태스크 트리 실행을 관리합니다. QParallelTaskTreeRunner::start () 메서드는 전달된 레시피를 무조건 시작하고 실행 가능한 모든 태스크 트리를 병렬로 유지합니다.
QMappedTaskTreeRunner매핑된 태스크 트리 실행을 관리합니다. QMappedTaskTreeRunner::start () 메서드는 지정된 키에 대해 지정된 레시피를 무조건 시작합니다. 동일한 키로 다른 태스크 트리가 이미 실행 중이면 재설정됩니다. 키가 다른 태스크 트리는 영향을 받지 않고 계속 실행됩니다.

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.