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

사용 하는 방법을 보여 주는이 예제는 concurrency::task, concurrency::cancellation_token_source, concurrency::cancellation_token, concurrency::task_completion_event, concurrency::timer, 및 concurrency::call 지연 후 완료 된 작업을 만들려면 클래스.이 메서드를 사용 하면 때때로 데이터에 대 한 폴링, 시간 제한을 소개, 지연, 미리 정한 시간에 대 한 사용자 입력을 처리 하는 루프를 작성 수 있습니다.

예제

다음 예제에서는 complete_aftercancel_after_timeout 함수를 보여 줍니다.complete_after 함수를 만듭니다는 task 개체는 지정 된 지연 시간 후에 완료 됩니다.사용 하는 timer 개체 및 call 개체를 설정 하는 task_completion_event 개체에 지정 된 지연 시간 후.사용 하 여는 task_completion_event 클래스, 스레드 후 완료 되는 작업을 정의할 수 있습니다 또는 다른 작업 값을 사용할 수 있는지 알립니다.이벤트를 설정 하는 경우 수신기 작업 완료 하 고 해당 연속 실행 되도록 예약 됩니다.

팁

에 대 한 자세한 내용은 timercall 비동기 에이전트 라이브러리의 일부인 클래스를 참조 하십시오. 비동기 메시지 블록.

cancel_after_timeout 함수 작성 complete_after 해당 작업에 지정 된 시간이 초과 되기 전에 완료 되지 않은 경우 작업을 취소 하는 함수입니다.cancel_after_timeout 함수는 두 개의 작업을 만듭니다.첫 번째 작업 성공 여부 및 제공 된 작업을 완료 한 후 완료. 두 번째 작업 실패를 나타내고 지정한 제한 시간 후에 완료.cancel_after_timeout 함수는 성공 또는 실패 작업 완료 시 실행 되는 연속 작업을 만듭니다.첫 번째 실패 임무가 완료 되 면 전체 작업 취소 토큰 소스 연속 작업을 취소 합니다.

// Creates a task that completes after the specified delay.
task<void> complete_after(unsigned int timeout)
{
    // A task completion event that is set when a timer fires.
    task_completion_event<void> tce;

    // Create a non-repeating timer.
    auto fire_once = new timer<int>(timeout, 0, nullptr, false);
    // Create a call object that sets the completion event after the timer fires.
    auto callback = new call<int>([tce](int)
    {
        tce.set();
    });

    // Connect the timer to the callback and start the timer.
    fire_once->link_target(callback);
    fire_once->start();

    // Create a task that completes after the completion event is set.
    task<void> event_set(tce);

    // Create a continuation task that cleans up resources and
    // and return that continuation task.
    return event_set.then([callback, fire_once]()
    {
        delete callback;
        delete fire_once;
    });
}

// Cancels the provided task after the specifed delay, if the task
// did not complete.
template<typename T>
task<T> cancel_after_timeout(task<T> t, cancellation_token_source cts, unsigned int timeout)
{
    // Create a task that returns true after the specified task completes.
    task<bool> success_task = t.then([](T)
    {
        return true;
    });
    // Create a task that returns false after the specified timeout.
    task<bool> failure_task = complete_after(timeout).then([]
    {
        return false;
    });

    // Create a continuation task that cancels the overall task 
    // if the timeout task finishes first.
    return (failure_task || success_task).then([t, cts](bool success)
    {
        if(!success)
        {
            // Set the cancellation token. The task that is passed as the
            // t parameter should respond to the cancellation and stop
            // as soon as it can.
            cts.cancel();
        }

        // Return the original task.
        return t;
    });
}

다음 예제에서는 범위 [0, 100000] 소수 개수 계산 여러 번.지정 된 제한 시간에 완료 되지 않은 경우 작업이 실패 합니다.count_primes 함수를 사용 하는 방법을 보여 줍니다 있는 cancel_after_timeout 함수입니다.프라임 주어진 범위의 개수 하 고 제공 된 시간에 작업이 완료 되지 않으면 실패 합니다.wmain 함수 호출을 count_primes 여러 번 작동 합니다.매번이 제한 시간을 절반.현재 제한 시간에 작업이 완료 되지 않습니다 후 프로그램이 종료 됩니다.

// Determines whether the input value is prime.
bool is_prime(int n)
{
    if (n < 2)
        return false;
    for (int i = 2; i < n; ++i)
    {
        if ((n % i) == 0)
            return false;
    }
    return true;
}

// Counts the number of primes in the range [0, max_value].
// The operation fails if it exceeds the specified timeout.
bool count_primes(unsigned int max_value, unsigned int timeout)
{
    cancellation_token_source cts;

    // Create a task that computes the count of prime numbers.
    // The task is canceled after the specified timeout.
    auto t = cancel_after_timeout(task<size_t>([max_value, timeout]
    {
        combinable<size_t> counts;
        parallel_for<unsigned int>(0, max_value + 1, [&counts](unsigned int n) 
        {
            // Respond if the overall task is cancelled by canceling 
            // the current task.
            if (is_task_cancellation_requested())
            {
                cancel_current_task();
            }
            // NOTE: You can replace the calls to is_task_cancellation_requested
            // and cancel_current_task with a call to interruption_point.
            // interruption_point();

            // Increment the local counter if the value is prime.
            if (is_prime(n))
            {
                counts.local()++;
            }
        });
        // Return the sum of counts across all threads.
        return counts.combine(plus<size_t>());
    }, cts.get_token()), cts, timeout);

    // Print the result.
    try
    {
        auto primes = t.get();
        wcout << L"Found " << primes << L" prime numbers within " 
              << timeout << L" ms." << endl;
        return true;
    }
    catch (const task_canceled& e)
    {
        wcout << L"The task timed out." << endl;
        return false;
    }
}

int wmain()
{
    // Compute the count of prime numbers in the range [0, 100000] 
    // until the operation fails.
    // Each time the test succeeds, the time limit is halved.

    unsigned int max = 100000;
    unsigned int timeout = 5000;

    bool success = true;
    do
    {
        success = count_primes(max, timeout);
        timeout /= 2;
    } while (success);
}
/* Sample output:
    Found 9592 prime numbers within 5000 ms.
    Found 9592 prime numbers within 2500 ms.
    Found 9592 prime numbers within 1250 ms.
    Found 9592 prime numbers within 625 ms.
    The task timed out.
*/

이 기법을 사용 하 여 지연 후 작업을 취소 하는 경우 전체 작업이 취소 된 후 시작 되지 않은 작업은 시작 되지 않습니다.그러나 취소에 적시에 응답할 수 있는 장기 실행 작업에 대 한 것이 중요 합니다.이 예는 count_primes 메서드 호출에서 concurrency::is_task_cancellation_requestedcancel_current_task 취소에 응답 하는 기능.(호출 하 여 concurrency::interruption_point 함수).작업을 취소 하는 방법에 대 한 자세한 내용은 참조 하십시오 PPL에서의 취소.

이 예제의 전체 코드는 다음과 같습니다.

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

using namespace concurrency;
using namespace std;

// Creates a task that completes after the specified delay.
task<void> complete_after(unsigned int timeout)
{
    // A task completion event that is set when a timer fires.
    task_completion_event<void> tce;

    // Create a non-repeating timer.
    auto fire_once = new timer<int>(timeout, 0, nullptr, false);
    // Create a call object that sets the completion event after the timer fires.
    auto callback = new call<int>([tce](int)
    {
        tce.set();
    });

    // Connect the timer to the callback and start the timer.
    fire_once->link_target(callback);
    fire_once->start();

    // Create a task that completes after the completion event is set.
    task<void> event_set(tce);

    // Create a continuation task that cleans up resources and
    // and return that continuation task.
    return event_set.then([callback, fire_once]()
    {
        delete callback;
        delete fire_once;
    });
}

// Cancels the provided task after the specifed delay, if the task
// did not complete.
template<typename T>
task<T> cancel_after_timeout(task<T> t, cancellation_token_source cts, unsigned int timeout)
{
    // Create a task that returns true after the specified task completes.
    task<bool> success_task = t.then([](T)
    {
        return true;
    });
    // Create a task that returns false after the specified timeout.
    task<bool> failure_task = complete_after(timeout).then([]
    {
        return false;
    });

    // Create a continuation task that cancels the overall task 
    // if the timeout task finishes first.
    return (failure_task || success_task).then([t, cts](bool success)
    {
        if(!success)
        {
            // Set the cancellation token. The task that is passed as the
            // t parameter should respond to the cancellation and stop
            // as soon as it can.
            cts.cancel();
        }

        // Return the original task.
        return t;
    });
}

// Determines whether the input value is prime.
bool is_prime(int n)
{
    if (n < 2)
        return false;
    for (int i = 2; i < n; ++i)
    {
        if ((n % i) == 0)
            return false;
    }
    return true;
}

// Counts the number of primes in the range [0, max_value].
// The operation fails if it exceeds the specified timeout.
bool count_primes(unsigned int max_value, unsigned int timeout)
{
    cancellation_token_source cts;

    // Create a task that computes the count of prime numbers.
    // The task is canceled after the specified timeout.
    auto t = cancel_after_timeout(task<size_t>([max_value, timeout]
    {
        combinable<size_t> counts;
        parallel_for<unsigned int>(0, max_value + 1, [&counts](unsigned int n) 
        {
            // Respond if the overall task is cancelled by canceling 
            // the current task.
            if (is_task_cancellation_requested())
            {
                cancel_current_task();
            }
            // NOTE: You can replace the calls to is_task_cancellation_requested
            // and cancel_current_task with a call to interruption_point.
            // interruption_point();

            // Increment the local counter if the value is prime.
            if (is_prime(n))
            {
                counts.local()++;
            }
        });
        // Return the sum of counts across all threads.
        return counts.combine(plus<size_t>());
    }, cts.get_token()), cts, timeout);

    // Print the result.
    try
    {
        auto primes = t.get();
        wcout << L"Found " << primes << L" prime numbers within " 
              << timeout << L" ms." << endl;
        return true;
    }
    catch (const task_canceled& e)
    {
        wcout << L"The task timed out." << endl;
        return false;
    }
}

int wmain()
{
    // Compute the count of prime numbers in the range [0, 100000] 
    // until the operation fails.
    // Each time the test succeeds, the time limit is halved.

    unsigned int max = 100000;
    unsigned int timeout = 5000;

    bool success = true;
    do
    {
        success = count_primes(max, timeout);
        timeout /= 2;
    } while (success);
}
/* Sample output:
    Found 9592 prime numbers within 5000 ms.
    Found 9592 prime numbers within 2500 ms.
    Found 9592 prime numbers within 1250 ms.
    Found 9592 prime numbers within 625 ms.
    The task timed out.
*/

코드 컴파일

코드를 컴파일하려면 복사한 다음 Visual Studio 프로젝트에 붙여 넣을 하거나 라는 파일에 붙여 넣을 작업 delay.cpp 및 다음 Visual Studio 명령 프롬프트 창에서 다음 명령을 실행 합니다.

cl.exe /EHsc task-delay.cpp

참고 항목

참조

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

cancellation_token_source 클래스

cancellation_token 클래스

task_completion_event 클래스

is_task_cancellation_requested 함수

cancel_current_task 함수

interruption_point 함수

timer 클래스

call 클래스

개념

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

비동기 메시지 블록

PPL에서의 취소