Udostępnij za pośrednictwem


Jak: Tworzenie zadania kończąca z opóźnieniem

W tym przykładzie przedstawiono sposób użycia concurrency::task, concurrency::cancellation_token_source, concurrency::cancellation_token, concurrency::task_completion_event, concurrency::timer, i concurrency::call klasy, aby utworzyć zadanie, w której jest wykonywane z opóźnieniem.Ta metoda służy do tworzenia pętli, które od czasu do czasu sondować w poszukiwaniu danych, wprowadzić limity czasu, opóźnić obsługę danych wprowadzanych przez użytkownika dla wyznaczonym czasie i tak dalej.

Przykład

W poniższym przykładzie pokazano complete_after i cancel_after_timeout funkcji.complete_after Funkcja tworzy task obiektu, do której jest wykonywane po podanym czasie opóźnienia.Używa timer obiektu i call obiektu w celu ustawienia task_completion_event obiektu po podanym czasie opóźnienia.Za pomocą task_completion_event klasy, można zdefiniować zadanie, w której jest wykonywane po wątek lub innego zadania sygnalizuje, że wartość jest dostępna.Jeśli zdarzenie, odbiornik zadania ukończone, a ich kontynuacji są zaplanowane do uruchomienia.

PoradaPorada

Aby uzyskać więcej informacji o timer i call klasy, które są częścią biblioteki agentów asynchronicznych, zobacz Asynchroniczne blokuje wiadomości.

cancel_after_timeout Funkcja opiera się na complete_after funkcji, aby anulować zadania, jeśli to zadanie nie zostanie ukończona przed danym limitu czasu.cancel_after_timeout Funkcja tworzy dwa zadania.Pierwsze oznacza sukces i kończy po zakończeniu zadania pod warunkiem; drugie zadanie wskazuje błąd i kończy po określonym czasie.cancel_after_timeout Funkcja tworzy zadanie utrzymania, który będzie uruchamiany po zakończeniu zadania sukces lub niepowodzenie.Zadanie awarii wykona pierwszy, kontynuacji anuluje token źródło, aby anulować ogólne zadanie.

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

Poniższy przykład oblicza liczbę liczb z zakresu [0, 100 000] wiele razy.Kończy się niepowodzeniem, jeśli nie zostanie ukończona w określonym czasie.count_primes Funkcja demonstruje, jak używać cancel_after_timeout funkcji.To oblicza, ile liczb pierwszych z podanego zakresu, a kończy się niepowodzeniem, jeśli zadanie nie zostanie ukończona w czasie pod warunkiem.wmain Wywołań funkcji count_primes funkcjonować wiele razy.Za każdym razem, połówki limit czasu.Program kończy się po operacji nie wykonuje się w limicie czasu bieżącego.

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

Gdy używasz tej techniki, aby anulować zadania z opóźnieniem, wszelkie nierozpoczętych zadań nie uruchamia się po ogólne zadanie zostało anulowane.Jednakże ważne jest dla wszystkich zadań długim odpowiedzieć na anulowanie w odpowiednim czasie.W tym przykładzie count_primes wywołania metody concurrency::is_task_cancellation_requested i cancel_current_task funkcje odpowiedzieć na anulowanie.(Alternatywnie, można wywołać concurrency::interruption_point funkcji).Aby uzyskać więcej informacji o anulowaniu zadania, zobacz Anulowanie w PPL.

Oto kompletny kod w tym przykładzie:

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

Kompilowanie kodu

Aby skompilować kod, skopiuj go i następnie wkleić go w projekcie programu Visual Studio lub wklej go w pliku o nazwie delay.cpp zadanie a następnie uruchom następujące polecenie w oknie wiersza polecenia usługi programu Visual Studio.

cl.exe /EHsc task-delay.cpp

Zobacz też

Informacje

zadanie klasy (współbieżności Runtime)

Klasa cancellation_token_source

Klasa cancellation_token

Klasa task_completion_event

Funkcja is_task_cancellation_requested

Funkcja cancel_current_task

Funkcja interruption_point

Timer, klasa

wywołanie klasy

Koncepcje

Zadanie równoległości (współbieżności Runtime)

Asynchroniczne blokuje wiadomości

Anulowanie w PPL