Sdílet prostřednictvím


Postupy: Vytvoření úlohy, která je dokončena po prodlevě

Tento příklad ukazuje, jak použít concurrency::task, concurrency::cancellation_token_source, concurrency::cancellation_token, concurrency::task_completion_event, concurrency::timer, a concurrency::call třídy k vytvoření úlohy, která provede po prodlevě.Tuto metodu můžete použít k vytvoření smyčky, které občas dotazování na data, zavést časové limity, zpracování vstupu uživatele na předem stanovenou dobu zpoždění a tak dále.

Příklad

Následující příklad ukazuje funkce complete_after a cancel_after_timeout.complete_after Funkce vytvoří task objekt, který dokončí po zadané prodlevě.Používá timer objekt a call objekt, který chcete nastavit task_completion_event objekt po zadané prodlevě.Při použití task_completion_event třídy, můžete definovat úkol dokončí po vlákno nebo jiný úkol signalizuje, že hodnota je k dispozici.Při události dokončit úkoly posluchače a jejich pokračování naplánováno spuštění.

Tip

Další informace týkající timer a call třídy, které jsou součástí knihovny asynchronní agenti, viz Asynchronní bloky zpráv.

cancel_after_timeout Funkce je založena na complete_after funkce, zrušit úlohu, pokud tento úkol není dokončen před daný časový limit.cancel_after_timeout Funkce vytvoří dva úkoly.První úkol označuje úspěch a skončí po dokončení zadané úlohy; druhý úkol označuje selhání a dokončí po určený časový limit.cancel_after_timeout Funkce vytvoří do pokračovací úlohy, která se spouští při dokončení úlohy úspěch nebo neúspěch.V případě selhání úlohy skončí první, zruší pokračování zdroji token zrušení obecný úkol.

// 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;
    });
}

Následující příklad vypočítá počet prvočísel v rozsahu [0, 100000] vícekrát.Operace se nezdaří, pokud nebyl proveden v daném časovém limitu.count_primes Funkce ukazuje, jak použít cancel_after_timeout funkce.Vrátí počet základen v daném rozsahu a se nezdaří, pokud úloha není dokončena v zadaný čas.wmain Volání funkce count_primes funkce vícekrát.Pokaždé, když poloviny časový limit.Aplikace se ukončí po operaci nedokončí v aktuálním časovém limitu.

// 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.
*/

Při použití této techniky zrušit úlohy po prodlevě, nebude možné spustit všechny nezahájené úkoly po obecný úkol je zrušena.Je však důležité pro dlouhotrvající úkoly reagovat na zrušení včas.V tomto příkladu count_primes volání metody concurrency::is_task_cancellation_requested a cancel_current_task funkce reagovat na zrušení. (Případně můžete zavolat concurrency::interruption_point funkce).Další informace o zrušení úlohy naleznete v tématu Zrušení v knihovně PPL.

Zde je kompletní kód v tomto příkladu:

// 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.
*/

Probíhá kompilace kódu

Kompilovat kód, zkopírujte jej a vložte do projektu sady Visual Studio nebo vložit do souboru s názvem úkol delay.cpp a potom spusťte následující příkaz v okně Příkazový řádek Visual Studio.

cl.exe /EHsc task-delay.cpp

Viz také

Referenční dokumentace

task – třída (Concurrency Runtime)

cancellation_token_source – třída

cancellation_token – třída

task_completion_event – třída

is_task_cancellation_requested – funkce

cancel_current_task – funkce

interruption_point – funkce

timer – třída

call – třída

Koncepty

Funkční paralelismus (Concurrency Runtime)

Asynchronní bloky zpráv

Zrušení v knihovně PPL