Sdílet prostřednictvím


Jak: vytvoření úkolu, který dokončí po prodlevě

Tento příklad ukazuje, jak používat concurrency::task, concurrency::cancellation_token_source, concurrency::cancellation_token, concurrency::task_completion_event, concurrency::timer, a concurrency::call třídy, chcete-li vytvořit úkol, který dokončí 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 complete_after a cancel_after_timeout funkce.complete_after Funkce vytvoří task objekt, který dokončí po zadané prodlevě.Používá timer objektu 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 úlohu, která dokončí po vlákno nebo jiný úkol signalizuje, že hodnota je k dispozici.Pokud je událost, 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říd, které jsou součástí knihovny asynchronní agenti, viz Asynchronní bloků zprávy.

cancel_after_timeout Funkce je založena na complete_after funkci, kterou chcete zrušit úlohu, je-li daný úkol není dokončen před daný časový limit.cancel_after_timeout Funkce vytvoří dva úkoly.První úkol označuje úspěch a dokončí po dokončení zadané úlohy; druhý úkol označuje chybu 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í zdroj 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 není dokončena v daném časovém limitu.count_primes Funkci demonstruje použití cancel_after_timeout funkce.Spočí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 pracovat více než jednou.Při každém poloviny časový limit.Aplikace se ukončí po operace dokončena v aktuální časový limit.

// 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 ke zrušení úkolů po prodlevě všech nezahájených úkolů se nespustí po zrušení obecný úkol.V každém případě je důležité pro všechny úkoly dlouhotrvající 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 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

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

cl.exe /EHsc task-delay.cpp

Viz také

Referenční dokumentace

úkol třídy (souběžnosti Runtime)

Třída cancellation_token_source

Třída cancellation_token

Třída task_completion_event

is_task_cancellation_requested funkce

cancel_current_task funkce

interruption_point funkce

Třída Timer

volání třídy

Koncepty

Úkol rovnoběžnosti (souběžnosti Runtime)

Asynchronní bloků zprávy

Zrušení v PPL