다음을 통해 공유


작업 병렬 처리(동시성 런타임)

이 문서에서는 동시성 런타임에서 작업 및 작업 그룹의 역할에 대해 설명합니다.작업(task)은 특정 업무를 수행하는 작업(work) 단위입니다.일반적으로 작업을 다른 작업과 병렬로 실행 및 추가, 더욱 세밀 한 작업으로 분리할 수 있습니다.작업 그룹은 작업 컬렉션을 구성합니다.

비동기 코드를 작성 하 고 비동기 작업이 완료 된 후 발생 하는 일부 작업을 사용할 때 작업을 사용 합니다.예를 들어, 비동기적으로 연속 작업을 사용할 수 있게 되 면 데이터를 처리 하면 나중에이 문서에서 설명 하 고 파일에서 읽기 작업을 사용할 수 있습니다.반대로 작업 그룹을 사용 하 여 병렬 작업을 더 작은 조각으로 분해 합니다.예를 들어 남은 작업을 두 개의 파티션으로 나누는 재귀 알고리즘이 있다고 가정해 봅니다.이러한 파티션을 동시에 실행 하 고 다음 나눈된 작업 완료를 기다리는 작업 그룹을 사용할 수 있습니다.

팁

병렬로 컬렉션의 각 요소를 동일한 루틴을 적용할 때 병렬 알고리즘을 사용 하는 같은 concurrency::parallel_for, 작업 또는 작업 그룹을 대신 합니다.병렬 알고리즘에 대한 자세한 내용은 병렬 알고리즘을 참조하십시오.

주요 사항

  • 참조를 통해 변수를 람다 식에 전달하는 경우 해당 변수의 수명이 작업 완료 시까지 유지되도록 해야 합니다.

  • 사용 작업 (의 concurrency::task 클래스) 비동기 코드를 작성 합니다.

  • 작업 그룹을 사용 (같은 concurrency::task_group 클래스 또는 concurrency::parallel_invoke 알고리즘) 병렬 작업을 더 작은 부분으로 분해 하 고 그러한 작은 부분을 완료 하 고 대기 해야 합니다.

  • 사용 된 concurrency::task::then 연속 문자를 만드는 방법.A 연속 다른 임무를 완료 하면 비동기적으로 실행 되는 작업입니다.비동기 작업의 체인을 형성 하는 연속 된 수를 연결할 수 있습니다.

  • 선행 작업이 완료 되 면도 때 선행 작업 취소 하거나 예외를 throw 작업 기반 연속 실행을 위해 항상 예정입니다.

  • 사용 concurrency::when_all 모든 구성원의 작업 집합을 완료 한 후에 완료 된 작업을 만들 수 있습니다.사용 concurrency::when_any 구성원 집합의 작업을 완료 한 후 완료 되는 작업을 만들 수 있습니다.

  • PPL 취소 메커니즘에는 작업 및 작업 그룹에 참여할 수 있습니다.자세한 내용은 PPL에서의 취소을 참조하십시오.

  • 런타임에 작업 및 작업 그룹에서 throw 된 예외를 처리 하는 방법을 보려면 동시성 런타임에서 예외 처리.

이 문서에서

  • 람다 식 사용

  • 작업 클래스

  • 연속 작업

  • 값에 따라 연속 작업에 따른 비교

  • 작업 작성

    • When_all 함수

    • When_any 함수

  • 지연 된 작업 실행

  • 작업 그룹

  • task_group을 structured_task_group과 비교

  • 예제

  • 강력한 프로그래밍

람다 식 사용

람다 식은 그 때문에 간결한 구문을 수행 하는 작업 및 작업 그룹에서 작업을 정의 하는 일반적인 방법입니다.사용 하 여 몇 가지 팁은 다음과 같습니다.

  • 작업에 일반적으로 백그라운드 스레드에서 실행 되므로 개체 수명 람다 식의 변수를 캡처할 때 주의 해야 합니다.값으로 변수를 캡처할 때 해당 변수의 복사본 람다 본문에서 이루어집니다.참조로 캡처하면 복사본이 이뤄집니다.따라서 해당 참조에 의해 캡처 모든 변수의 수명은 사용 하는 작업 outlives 확인 하십시오.

  • 일반적으로 캡처 없는 변수는 스택에 할당 됩니다.즉, 스택에 할당 된 개체의 멤버 변수 캡처 안 되는.

  • 어떤 값과 참조로 파악 하는 식별 하는 데 도움이 되는 람다 식에 캡처 변수에 대 한 명시적 이어야 합니다.이러한 이유로 하지 좋습니다 사용 하는 것은 [=] 또는 [&] 람다 식에 대 한 옵션.

일반적인 패턴은 연속 체인의 작업을 변수에 할당 하 고 다른 작업 해당 변수를 읽을 때입니다.다른 변수 사본을 각 연속 작업을 포함할 수 있으므로 값을 캡처할 수 없습니다.스택 할당에 대 한 변수 변수가 더 이상 유효 하지 않으므로 참조로도 캡처할 수 없습니다.

이 문제를 해결 하려면 스마트 포인터를 같이 사용 std::shared_ptr변수를 배치 하 고 스마트 포인터를 값으로 전달 합니다.이렇게 하면 기본 개체를 할당할 수 및 읽고 사용 하는 작업을 outlive 합니다.변수는 포인터 또는 참조 횟수가 계산 된 핸들이 있는 경우에이 기법을 사용 (^) Windows 런타임 개체입니다.기본 예제는 다음과 같습니다.

// lambda-task-lifetime.cpp
// compile with: /EHsc
#include <ppltasks.h>
#include <iostream>
#include <string>

using namespace concurrency;
using namespace std;

task<wstring> write_to_string()
{
    // Create a shared pointer to a string that is 
    // assigned to and read by multiple tasks.
    // By using a shared pointer, the string outlives
    // the tasks, which can run in the background after
    // this function exits.
    auto s = make_shared<wstring>(L"Value 1");

    return create_task([s] 
    {
        // Print the current value.
        wcout << L"Current value: " << *s << endl;
        // Assign to a new value.
        *s = L"Value 2";

    }).then([s] 
    {
        // Print the current value.
        wcout << L"Current value: " << *s << endl;
        // Assign to a new value and return the string.
        *s = L"Value 3";
        return *s;
    });
}

int wmain()
{
    // Create a chain of tasks that work with a string.
    auto t = write_to_string();

    // Wait for the tasks to finish and print the result.
    wcout << L"Final value: " << t.get() << endl;
}

/* Output:
    Current value: Value 1
    Current value: Value 2
    Final value: Value 3
*/

람다 식에 대 한 자세한을 참조 하십시오. C + +에서 람다 식.

Top

작업 클래스

사용할 수 있는 concurrency::task 종속 작업 집합으로 작업을 구성 하는 클래스.이 복합 모델의 개념으로 지 연속.연속 사용 코드가 실행 될 때 이전, 또는 앞 내용을, 작업을 완료 합니다.선행 작업의 결과가 입력 하나 이상의 연속 작업으로 전달 됩니다.선행 작업이 완료 되 면 연속 작업에 대기 중인 실행 하도록 예약 됩니다.각 연속 작업 선행 작업의 결과의 복사본을 받습니다.결과적으로 연속 작업 선행 작업을 함으로써 체인 작업을 만들기 다른 연속을 수도 있습니다.연속 된 임의 길이 체인을 특정 의존 관계에 있는 작업을 만들 수 있습니다.또한 실행 중인 작업 취소 작업을 하기 전에 하나를 시작 하거나 협력 방식으로 참여할 수 있습니다.이 취소 모델에 대 한 자세한 내용은 PPL에서의 취소.

task템플릿 클래스가입니다.형식 매개 변수 T 작업에 의해 생성 되는 결과의 형식입니다.이 형식을 사용할 수 있습니다 void 작업 값을 반환 하지 않는 경우.T사용할 수 있는 const 한정자.

작업을 만들 때 제공 된 작업 함수 는 본문 작업을 수행 합니다.이 작업의 함수는 람다 함수, 함수 포인터나 함수 개체의 형태로 제공 됩니다.호출 결과 얻지 않고 완료 작업을 대기 하는 concurrency::task::wait 메서드.task::wait 메서드가 반환 된 concurrency::task_status 작업이 완료 되거나 취소 된 여부를 설명 하는 값.작업의 결과 얻기 위해 호출 하는 concurrency::task::get 메서드.이 메서드를 호출 합니다. task::wait 작업 완료 날짜와 현재 스레드 실행 블록에 대 한 결과가 있을 때까지 기다려야 합니다.

다음 예제에서는 작업의 결과 대 한 대기 만들고 해당 값을 표시 하는 방법을 보여 줍니다.이 설명서의 예제는 좀 더 간결한 구문을 제공 하므로 람다 함수를 사용 합니다.그러나 작업을 사용 하는 경우에서는 함수 포인터와 함수 개체 사용할 수도 있습니다.

// basic-task.cpp
// compile with: /EHsc
#include <ppltasks.h>
#include <iostream>

using namespace concurrency;
using namespace std;

int wmain()
{
    // Create a task.
    task<int> t([]()
    {
        return 42;
    });

    // In this example, you don't necessarily need to call wait() because
    // the call to get() also waits for the result.
    t.wait();

    // Print the result.
    wcout << t.get() << endl;
}

/* Output:
    42
*/

Concurrency::create_task 함수를 사용 하면 사용할 수 있는 auto 키워드는 형식을 선언 하는 대신.예를 들어, 인쇄 항등 매트릭스를 만들고 다음 코드를 고려 하십시오.

// create-task.cpp
// compile with: /EHsc
#include <ppltasks.h>
#include <string>
#include <iostream>
#include <array>

using namespace concurrency;
using namespace std;

int wmain()
{
    task<array<array<int, 10>, 10>> create_identity_matrix([]
    {
        array<array<int, 10>, 10> matrix;
        int row = 0;
        for_each(begin(matrix), end(matrix), [&row](array<int, 10>& matrixRow) 
        {
            fill(begin(matrixRow), end(matrixRow), 0);
            matrixRow[row] = 1;
            row++;
        });
        return matrix;
    });

    auto print_matrix = create_identity_matrix.then([](array<array<int, 10>, 10> matrix)
    {
        for_each(begin(matrix), end(matrix), [](array<int, 10>& matrixRow) 
        {
            wstring comma;
            for_each(begin(matrixRow), end(matrixRow), [&comma](int n) 
            {
                wcout << comma << n;
                comma = L", ";
            });
            wcout << endl;
        });
    });

    print_matrix.wait();
}
/* Output:
    1, 0, 0, 0, 0, 0, 0, 0, 0, 0
    0, 1, 0, 0, 0, 0, 0, 0, 0, 0
    0, 0, 1, 0, 0, 0, 0, 0, 0, 0
    0, 0, 0, 1, 0, 0, 0, 0, 0, 0
    0, 0, 0, 0, 1, 0, 0, 0, 0, 0
    0, 0, 0, 0, 0, 1, 0, 0, 0, 0
    0, 0, 0, 0, 0, 0, 1, 0, 0, 0
    0, 0, 0, 0, 0, 0, 0, 1, 0, 0
    0, 0, 0, 0, 0, 0, 0, 0, 1, 0
    0, 0, 0, 0, 0, 0, 0, 0, 0, 1
*/

사용할 수 있는 create_task 동등한 작업을 만드는 기능.

auto create_identity_matrix = create_task([]
{
    array<array<int, 10>, 10> matrix;
    int row = 0;
    for_each(begin(matrix), end(matrix), [&row](array<int, 10>& matrixRow) 
    {
        fill(begin(matrixRow), end(matrixRow), 0);
        matrixRow[row] = 1;
        row++;
    });
    return matrix;
});

작업을 실행 하는 동안 예외가 발생 하면 런타임에서 해당 후속 호출에 예외 마샬링합니다 task::get 또는 task::wait, 또는 작업을 기준으로 연속으로.작업 예외 처리 메커니즘에 대 한 자세한 내용은 동시성 런타임에서 예외 처리.

사용 예 task, concurrency::task_completion_event, 취소를 참조 하십시오 연습: 작업 및 XML HTTP 요청(IXHR2)을 사용하여 연결.(의 task_completion_event 클래스는이 문서의 뒷부분에서 설명 합니다.)

팁

작업에 관련 된 세부 정보를 보려면 Windows 스토어 응용 프로그램을 참조 하십시오. Asynchronous programming in C++C++로 Windows 스토어 앱용 비동기 작업 만들기.

Top

연속 작업

비동기 프로그래밍에서는 하나의 비동기 작업에서 해당 작업이 완료될 때 두 번째 작업을 호출하고 이 작업에 데이터를 전달하는 것이 매우 일반적입니다.일반적으로 이러한 콜백 메서드를 사용 하 여 수행 됩니다.동시성 런타임에서에서 동일한 기능을 제공 연속 작업.연속 작업은 선행 작업이라고 하는 다른 작업이 완료될 때 선행 작업에 의해 호출되는 비동기 작업입니다.연속 문자를 사용 하 여 수행할 수 있습니다.

  • 데이터를 앞의 내용을 연속으로 전달 합니다.

  • 연속 된 호출 또는 호출에서 정확한 조건을 지정 합니다.

  • 연속 시작 되기 전에 또는 동시 실행 되는 동안 취소 합니다.

  • 연속 된 일정에 대 한 힌트를 제공 합니다.(적용 대상 Windows 스토어 응용 프로그램에만 있습니다.자세한 내용은 C++로 Windows 스토어 앱용 비동기 작업 만들기를 참조하십시오.

  • 앞의 동일한 내용 여러 연속 된 호출 합니다.

  • 전체 또는 여러 antecedents를 완료 하면 하나의 연속을 호출 합니다.

  • 체인 내린 차례에 길이입니다.

  • 앞으로 내용을 throw 되는 예외를 처리 하는 연속을 사용 합니다.

이러한 기능을 사용 하면 첫 번째 작업이 완료 되 면 하나 이상의 작업을 실행할 수 있습니다.예를 들어, 첫 번째 작업은 디스크에서 읽은 후에 파일을 압축 하는 연속을 만들 수 있습니다.

다음 예제를 사용 하는 이전 수정의 concurrency::task::then 사용할 수 있는 경우에 선행 작업의 값을 출력 하는 연속 예약 방법.

// basic-continuation.cpp
// compile with: /EHsc
#include <ppltasks.h>
#include <iostream>

using namespace concurrency;
using namespace std;

int wmain()
{
    auto t = create_task([]() -> int
    {
        return 42;
    });

    t.then([](int result)
    {
        wcout << result << endl;
    }).wait();

    // Alternatively, you can chain the tasks directly and
    // eliminate the local variable.
    /*create_task([]() -> int
    {
        return 42;
    }).then([](int result)
    {
        wcout << result << endl;
    }).wait();*/
}

/* Output:
    42
*/

체인 고 길이 작업을 중첩할 수 있습니다.여러 개의 연속 된 작업을 할 수도 있습니다.다음 예제에서는 이전 작업의 값이 3 배 증가 하는 기본 연속 체인을 보여 줍니다.

// continuation-chain.cpp
// compile with: /EHsc
#include <ppltasks.h>
#include <iostream>

using namespace concurrency;
using namespace std;

int wmain()
{
    auto t = create_task([]() -> int
    { 
        return 0;
    });

    // Create a lambda that increments its input value.
    auto increment = [](int n) { return n + 1; };

    // Run a chain of continuations and print the result.
    int result = t.then(increment).then(increment).then(increment).get();
    wcout << result << endl;
}

/* Output:
    3
*/

다른 작업의 연속을 반환할 수도 있습니다.다음이 작업 취소 없음 있으면 다음 계속 하기 전에 실행 됩니다.이 기술은 이라고 비동기 래핑 해제.비동기 래핑 해제 백그라운드에서 추가 작업을 수행 하려는 현재 작업이 현재 스레드를 차단 하지 않을 때 유용 합니다.(일반적으로 Windows 스토어 응용 프로그램, 연속 된 UI 스레드에서 실행할 수 있습니다).다음 예제에서는 세 가지 작업을 보여 줍니다.첫 번째 작업 연속 작업 보다 먼저 실행 되는 다른 작업을 반환 합니다.

// async-unwrapping.cpp
// compile with: /EHsc
#include <ppltasks.h>
#include <iostream>

using namespace concurrency;
using namespace std;

int wmain()
{
    auto t = create_task([]()
    {
        wcout << L"Task A" << endl;

        // Create an inner task that runs before any continuation
        // of the outer task.
        return create_task([]()
        {
            wcout << L"Task B" << endl;
        });
    });

    // Run and wait for a continuation of the outer task.
    t.then([]()
    {
        wcout << L"Task C" << endl;
    }).wait();
}

/* Output:
    Task A
    Task B
    Task C
*/
중요중요

때 작업의 연장선에서 반환 형식의 중첩된 작업 N, 결과 작업 형식이 N가 아니라 task<N>, 및 중첩 된 작업을 완료 하면 완료.즉, 계속 중첩 된 작업의 래핑 해제를 수행 합니다.

Top

값에 따라 연속 작업에 따른 비교

부여는 task 형식이 반환 되는 개체 T, 형식의 값을 제공할 수 있습니다 T 또는 task<T> 연속 작업을 합니다.형식을 사용 하는 연속 T 이라고는 값에 따라 연속.선행 작업이 오류 없이 완료 될 때 취소 되지 값에 따라 연속 실행 하도록 예약 됩니다.형식을 사용 하는 연속 task<T> 로 알려진 매개 변수는 연속 작업 기반.선행 작업이 완료 되 면도 때 선행 작업 취소 하거나 예외를 throw 작업 기반 연속 실행을 위해 항상 예정입니다.다음 호출 수 task::get 선행 작업의 결과 얻을 수 있습니다.선행 작업이 취소 된 경우 task::get throw concurrency::task_canceled.선행 작업은 예외를 throw 하는 경우 task::get 해당 예외를 다시 throw 합니다.작업 기반 연속의 선행 작업을 취소 하면 취소 된 것으로 표시 되지 않습니다.

Top

작업 작성

설명의 concurrency::when_allconcurrency::when_any 함수를 사용 하는 데 도움이 일반적인 패턴을 구현 하는 여러 작업을 작성 합니다.

Dd492427.collapse_all(ko-kr,VS.110).gifWhen_all 함수

when_all 함수는 일련의 작업을 완료 한 후 완료 작업을 생성 합니다.이 함수에서 반환 된 상의 집합에서 각 작업의 결과 포함 하는 개체.기본 예제를 사용 하 여 when_all 세 가지 다른 작업의 완료를 나타내는 작업을 만들 수 있습니다.

// join-tasks.cpp
// compile with: /EHsc
#include <ppltasks.h>
#include <array>
#include <iostream>

using namespace concurrency;
using namespace std;

int wmain()
{
    // Start multiple tasks.
    array<task<void>, 3> tasks = 
    {
        create_task([] { wcout << L"Hello from taskA." << endl; }),
        create_task([] { wcout << L"Hello from taskB." << endl; }),
        create_task([] { wcout << L"Hello from taskC." << endl; })
    };

    auto joinTask = when_all(begin(tasks), end(tasks));

    // Print a message from the joining thread.
    wcout << L"Hello from the joining thread." << endl;

    // Wait for the tasks to finish.
    joinTask.wait();
}

/* Sample output:
    Hello from the joining thread.
    Hello from taskA.
    Hello from taskC.
    Hello from taskB.
*/

[!참고]

전달 하는 작업 when_all 일정 이어야 합니다.즉, 모두 동일한 형식을 반환 해야 합니다.

도 수는 && 작업 집합이 완료 되 면 다음과 같이 완료 된 작업을 생성 하는 구문을.

auto t = t1 && t2; // same as when_all

연속과 함께 사용 하는 것이 일반적입니다 when_all 작업을 마친 후 작업을 수행할 수 있습니다.합 세 작업을 인쇄 하는 이전 예제를 수정 각각 생성 하는 int 결과입니다.

// Start multiple tasks.
array<task<int>, 3> tasks =
{
    create_task([]() -> int { return 88; }),
    create_task([]() -> int { return 42; }),
    create_task([]() -> int { return 99; })
};

auto joinTask = when_all(begin(tasks), end(tasks)).then([](vector<int> results)
{
    wcout << L"The sum is " 
          << accumulate(begin(results), end(results), 0)
          << L'.' << endl;
});

// Print a message from the joining thread.
wcout << L"Hello from the joining thread." << endl;

// Wait for the tasks to finish.
joinTask.wait();

/* Output:
    Hello from the joining thread.
    The sum is 229.
*/

이 예제에서는 또한 지정할 수 task<vector<int>> 작업 기반 연속 생성 합니다.

주의 정보주의

작업 집합의 모든 작업이 취소 하거나 예외를 throw 하는 경우 when_all 즉시 완료 되 고 남은 작업이 완료 되도록 기다리지 않습니다.예외가 throw 되 면 호출 하면 런타임 예외를 다시 throw task::get 또는 task::wait 에 있는 task 개체는 when_all 반환 합니다.둘 이상의 작업을 throw 하면 런타임은 중 하나를 선택 합니다.하나에서 예외를 throw 하는 경우 모든 작업을 완료할 때까지 기다리는 것을 확인 하십시오.

Top

Dd492427.collapse_all(ko-kr,VS.110).gifWhen_any 함수

when_any 함수 작업 집합에서 첫 번째 작업을 완료 하면 완료 된 작업을 만듭니다.이 함수에서 반환 된 std::pair 인덱스 집합에서 해당 작업의 완료 된 작업의 결과 포함 하는 개체.

when_any 함수는 다음과 같은 시나리오에서 특히 유용 합니다.

  • 중복 작업입니다.사용 되는 알고리즘 또는 여러 가지 방법으로 수행할 수 있는 작업을 고려해 야 합니다.사용할 수 있는 when_any 먼저 완료 작업을 선택 하 고 나머지 작업을 취소 하는 함수.

  • 작업을 인터리브입니다.여러 작업을 시작할 수 있습니다 모든 마침 사용 하 고 있어야 하는 when_any 각 작업이 완료 되는 대로 결과 처리 하는 함수.하나의 작업이 완료 된 후 하나 이상의 추가 작업을 시작할 수 있습니다.

  • 조절 대상된 작업입니다.사용할 수 있는 when_any 동시 작업의 수를 제한 하 여 이전 시나리오를 확장 하는 함수.

  • 만료 된 작업입니다.사용할 수 있는 when_any 함수를 하나 이상의 작업 및 작업을 완료 한 후 특정 시간 범위를 선택 합니다.

와 마찬가지로 when_all를 포함 하는 연속 사용 하는 것이 일반적입니다 when_any 첫 번째 집합의 작업 완료 시 작업을 수행 합니다.기본 예제를 사용 하 여 when_any 첫 번째 세 개의 다른 작업을 완료 하면 완료 된 작업을 만들 수 있습니다.

// select-task.cpp
// compile with: /EHsc
#include <ppltasks.h>
#include <array>
#include <iostream>

using namespace concurrency;
using namespace std;

int wmain()
{
    // Start multiple tasks.
    array<task<int>, 3> tasks = {
        create_task([]() -> int { return 88; }),
        create_task([]() -> int { return 42; }),
        create_task([]() -> int { return 99; })
    };

    // Select the first to finish.
    when_any(begin(tasks), end(tasks)).then([](pair<int, size_t> result)
    {
        wcout << "First task to finish returns "
              << result.first
              << L" and has index "
              << result.second
              << L'.' << endl;
    }).wait();
}

/* Sample output:
    First task to finish returns 42 and has index 1.
*/

이 예제에서는 또한 지정할 수 task<pair<int, size_t>> 작업 기반 연속 생성 합니다.

[!참고]

마찬가지로 when_all, 전달 하는 작업 when_any 모두 동일한 형식을 반환 해야 합니다.

도 수는 || 작업 집합에서 첫 번째 작업이 완료 되 면 다음과 같이 완료 된 작업을 생성 하는 구문을.

auto t = t1 || t2; // same as when_any

Top

지연 된 작업 실행

조건이 만족 될 때까지 작업의 실행을 지연 하거나 외부 이벤트에는 작업을 시작할 수 있습니다.예를 들어, 비동기 프로그래밍의 경우에 I/O 완료 이벤트에 응답 하는 작업을 시작 해야 합니다.

두 가지 방법으로이 작업을 수행 하는 연속 사용 또는 작업을 시작 하 고 작업의 작업 함수 내에 이벤트를 대기 됩니다.그러나, 있는 경우 다음이 방법 중 하나를 사용할 수 없습니다.예를 들어 연속을 만들기 위해서는 선행 작업이 있어야 합니다.그러나 선행 작업 하지 않은 경우 만들 수는 작업 완료 이벤트 및 나중에 사용할 수 있을 때 선행 작업 완료 이벤트를 연결 합니다.또한 또한 대기 작업은 스레드를 차단 하기 때문에 작업 완료 이벤트를 사용 하 여 비동기 작업이 완료 되 면 작업을 수행 하 고 따라서 스레드 약속 수 있습니다.

Concurrency::task_completion_event 클래스는 데 도움이 됩니다 이러한 구성 작업을 단순화 합니다.같은 task 클래스 형식 매개 변수 T 작업에 의해 생성 되는 결과의 형식입니다.이 형식을 사용할 수 있습니다 void 작업 값을 반환 하지 않는 경우.T사용할 수 있는 const 한정자.일반적으로 task_completion_event 개체 스레드 또는 신호 수 작업의 값을 사용할 수 있을 때에 제공 됩니다.동시에 하나 이상의 작업이 해당 이벤트의 수신기로 설정 됩니다.이벤트가 설정 되 면 수신기 작업을 완료 하 고의 연속 실행 되도록 예약 됩니다.

사용 예 task_completion_event 지연 후 완료 되는 작업을 구현 하려면 방법: 지연 후 완료되는 작업 만들기.

Top

작업 그룹

작업 그룹은 작업 컬렉션을 구성합니다.작업 그룹은 작업 가로채기 큐에 작업을 넣습니다.스케줄러는 이 큐에서 작업을 제거하고 사용 가능한 컴퓨팅 리소스에서 해당 작업을 실행합니다.작업 그룹에 작업을 추가한 후 모든 작업이 끝날 때까지 기다리거나 아직 시작되지 않은 작업을 취소할 수 있습니다.

PPL을 사용 하는 concurrency::task_groupconcurrency::structured_task_group 작업 그룹을 나타내는 클래스와 concurrency::task_handle 이러한 그룹에서 실행할 작업을 나타내는 클래스입니다.task_handle 클래스는 작업을 수행하는 코드를 캡슐화합니다.같은 task 클래스, 작업 함수는 람다 함수, 함수 포인터나 함수 개체의 형태로 제공 합니다.일반적으로 task_handle 개체를 직접 사용할 필요는 없습니다.대신 작업 함수를 작업 그룹에 전달하면 작업 그룹은 task_handle 개체를 만들고 관리합니다.

PPL은 작업 그룹을 비구조적 작업 그룹 및 구조적 작업 그룹이라는 두 개의 범주로 분할합니다.PPL을 사용 하는 task_group 구조화 되지 않은 작업 그룹을 나타내는 클래스와 structured_task_group 구조화 된 작업 그룹을 나타내는 클래스입니다.

중요중요

PPL은 또한 정의 concurrency::parallel_invoke 알고리즘을 사용 하는 structured_task_group 작업을 병렬로 실행 하는 클래스.parallel_invoke 알고리즘의 구문이 더 간결하므로 가능하면 structured_task_group 클래스 대신 이 알고리즘을 사용하는 것이 좋습니다.병렬 알고리즘 항목에서 parallel_invoke에 대해 더 자세히 설명합니다.

동시에 실행할 독립적인 작업이 여러 개 있고 계속하지 않고 모든 작업이 끝날 때까지 기다려야 하는 경우 parallel_invoke를 사용합니다.이 기술은 주로 이라고 조인 및 포크 병렬 처리 합니다.동시에 실행할 독립적인 작업이 여러 개 있지만 나중에 작업이 끝날 때까지 기다리려는 경우 task_group을 사용합니다.예를 들어 task_group개체에 작업을 추가하고 다른 함수 또는 다른 스레드에서 작업이 끝날 때까지 기다릴 수 있습니다.

작업 그룹에서는 취소 개념을 지원합니다.취소를 사용하면 전체 작업(operation)을 취소하려는 모든 활성 작업(task)에 신호를 보낼 수 있습니다.취소를 사용하면 아직 시작되지 않은 작업을 시작되지 않게 할 수도 있습니다.취소에 대한 자세한 내용은 PPL에서의 취소를 참조하십시오.

런타임에서는 관련된 작업 그룹이 끝나기를 기다릴 때 작업에서 예외를 throw하고 해당 예외를 처리할 수 있게 하는 예외 처리 모델을 제공합니다.예외 처리 모델에 대한 자세한 내용은 동시성 런타임에서 예외 처리를 참조하십시오.

Top

task_group을 structured_task_group과 비교

사용 하는 것이 좋습니다 있지만 task_group 또는 parallel_invoke 대신에 structured_task_group 클래스, 사용 하려는 경우 structured_task_group, 예를 들어, 작성할 때 다양 한 작업을 수행 하거나 취소를 지원 해야 하는 병렬 알고리즘.이 단원에서는 task_group 클래스와 structured_task_group 클래스의 차이점에 대해 설명합니다.

task_group 클래스는 스레드로부터 안전합니다.따라서 작업을 추가할 수 있습니다는 task_group 개체를 여러 스레드에서 대기 및 취소는 task_group 개체를 여러 스레드에서.structured_task_group 개체의 생성과 소멸은 동일한 어휘 범위에서 발생해야 합니다.또한 structured_task_group 개체에 대한 모든 작업은 동일한 스레드에서 발생해야 합니다.이 규칙에 예외는 concurrency::structured_task_group::cancelconcurrency::structured_task_group::is_canceling 메서드.자식 작업은 언제든지 이러한 메서드를 호출하여 부모 작업 그룹을 취소하거나 취소를 확인할 수 있습니다.

추가 작업을 실행할 수는 task_group 호출 된 후 개체의 concurrency::task_group::wait 또는 concurrency::task_group::run_and_wait 메서드.추가 작업을 실행할 수 없습니다 반대로, structured_task_group 호출 된 후 개체의 concurrency::structured_task_group::wait 또는 concurrency::structured_task_group::run_and_wait 메서드.

structured_task_group 클래스는 스레드 간에 동기화하지 않으므로 task_group 클래스보다 실행 오버헤드가 적습니다.따라서 여러 스레드에서 작업을 예약할 필요가 없고 parallel_invoke 알고리즘을 사용할 수 없는 경우 structured_task_group 클래스를 사용하면 성능이 높은 코드를 작성할 수 있습니다.

다른 structured_task_group 개체 내에 있는 structured_task_group 개체를 사용하는 외부 개체를 완료하기 전에 먼저 내부 개체를 완료하고 소멸시켜야 합니다.task_group 클래스를 사용하는 경우에는 외부 그룹을 완료하기 전에 중첩된 작업 그룹을 완료할 필요가 없습니다.

비구조적 작업 그룹과 구조적 작업 그룹은 다양한 방식으로 작업 핸들을 사용합니다.작업 함수를 task_group 개체에 직접 전달할 수 있으며 그러면 task_group 개체에서 자동으로 작업을 만들고 관리합니다.structured_task_group 클래스를 사용하려면 각 작업의 task_handle 개체를 관리해야 합니다.관련된 structured_task_group 개체의 수명이 지속되는 동안 모든 task_handle 개체가 유효한 상태로 유지되어야 합니다.사용은 concurrency::make_task 만들려면 함수는 task_handle 다음 기본 예제와 같이 개체:

// make-task-structure.cpp
// compile with: /EHsc
#include <ppl.h>

using namespace concurrency;

int wmain()
{
   // Use the make_task function to define several tasks.
   auto task1 = make_task([] { /*TODO: Define the task body.*/ });
   auto task2 = make_task([] { /*TODO: Define the task body.*/ });
   auto task3 = make_task([] { /*TODO: Define the task body.*/ });

   // Create a structured task group and run the tasks concurrently.

   structured_task_group tasks;

   tasks.run(task1);
   tasks.run(task2);
   tasks.run_and_wait(task3);
}

여러 가지 작업이 있는 경우에 사용할 작업 핸들을 관리하려면 _malloca와 같은 스택 할당 루틴 또는 std::vector와 같은 컨테이너 클래스를 사용합니다.

task_groupstructured_task_group 모두 취소 기능을 지원합니다.취소에 대한 자세한 내용은 PPL에서의 취소를 참조하십시오.

Top

예제

다음 기본 예제에서는 작업 그룹을 사용하는 방법을 보여 줍니다.이 예제에서는 parallel_invoke 알고리즘을 사용하여 두 작업을 병렬로 수행합니다.각 작업은 하위 작업을 task_group 개체에 추가합니다.task_group 클래스를 사용하면 여러 작업이 이 개체에 작업을 동시에 추가할 수 있습니다.

// using-task-groups.cpp
// compile with: /EHsc
#include <ppl.h>
#include <sstream>
#include <iostream>

using namespace concurrency;
using namespace std;

// Prints a message to the console.
template<typename T>
void print_message(T t)
{
   wstringstream ss;
   ss << L"Message from task: " << t << endl;
   wcout << ss.str(); 
}

int wmain()
{  
   // A task_group object that can be used from multiple threads.
   task_group tasks;

   // Concurrently add several tasks to the task_group object.
   parallel_invoke(
      [&] {
         // Add a few tasks to the task_group object.
         tasks.run([] { print_message(L"Hello"); });
         tasks.run([] { print_message(42); });
      },
      [&] {
         // Add one additional task to the task_group object.
         tasks.run([] { print_message(3.14); });
      }
   );

   // Wait for all tasks to finish.
   tasks.wait();
}

이 예제를 실행하면 다음과 같은 샘플 결과가 출력됩니다.

Message from task: Hello
Message from task: 3.14
Message from task: 42

parallel_invoke 알고리즘은 작업을 동시에 실행하므로 출력 메시지의 순서가 다를 수 있습니다.

parallel_invoke 알고리즘을 사용하는 방법을 보여 주는 전체 예제를 보려면 방법: parallel_invoke를 사용하여 병렬 정렬 루틴 작성방법: parallel_invoke를 사용하여 병렬 작업 실행을 참조하십시오.task_group 클래스를 사용하여 비동기 미래를 구현하는 전체 예제를 보려면 연습: 미래 구현을 참조하십시오.

Top

강력한 프로그래밍

취소, 작업, 작업 그룹 및 병렬 알고리즘을 사용할 때 예외 처리의 역할을 이해 해야 합니다.예를 들어 병렬 작업 트리에서 취소된 작업으로 인해 자식 작업이 실행되지 않게 됩니다.자식 작업 중 하나가 사용자의 응용 프로그램에 중요한 작업(예: 리소스 해제)을 수행하는 경우 이로 인해 문제가 발생할 수 있습니다.또한 자식 작업에서 예외를 throw하면 해당 예외가 개체 소멸자를 통해 전파되고 응용 프로그램에서 정의되지 않은 동작이 발생할 수 있습니다.이러한 지점을 보여 주는 예제를 보려면 병렬 패턴 라이브러리의 유용한 정보 문서에 있는 Understand how Cancellation and Exception Handling Affect Object Destruction 단원을 참조하십시오.PPL의 취소 및 예외 처리 모델에 대한 자세한 내용은 PPL에서의 취소동시성 런타임에서 예외 처리를 참조하십시오.

Top

관련 항목

제목

설명

방법: parallel_invoke를 사용하여 병렬 정렬 루틴 작성

parallel_invoke 알고리즘을 사용하여 바이토닉 정렬 알고리즘의 성능을 향상시키는 방법을 보여 줍니다.

방법: parallel_invoke를 사용하여 병렬 작업 실행

parallel_invoke 알고리즘을 사용하여 공유 데이터 소스에 대해 여러 작업을 수행하는 프로그램의 성능을 향상시키는 방법을 보여 줍니다.

방법: 지연 후 완료되는 작업 만들기

사용 하는 방법을 보여 줍니다 있는 task, cancellation_token_source, cancellation_token, 및 task_completion_event 지연 후 완료 된 작업을 만들려면 클래스.

연습: 미래 구현

동시성 런타임의 기존 기능을 결합하여 더 많은 작업을 수행하는 방법을 보여 줍니다.

PPL(병렬 패턴 라이브러리)

동시 응용 프로그램 개발을 위해 명령형 프로그래밍 모델을 제공하는 PPL에 대해 설명합니다.

참조

작업 클래스(동시성 런타임)

task_completion_event 클래스

when_all 함수

when_any 함수

task_group 클래스

parallel_invoke 함수

structured_task_group 클래스