Udostępnij za pośrednictwem


Porady: tworzenie zadania kończonego po opóźnieniu

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, które zakończy z opóźnieniem.Metoda ta jest przydatna do tworzenia pętli, które od czasu do czasu pobierania danych, wprowadzić limity czasu, opóźniać obsługi danych wejściowych użytkownika dla wyznaczonym czasie i tak dalej.

Przykład

W poniższym przykładzie pokazano complete_after i cancel_after_timeout funkcje.complete_after Funkcja tworzy task obiekt, który zakończy się po podanym czasie opóźnienia.Używa on timer obiektu i call obiekt, aby ustawić task_completion_event obiektu po podanym czasie opóźnienia.Za pomocą task_completion_event klasy, można zdefiniować zadania, który zakończy się po wątku lub innego zadania sygnalizuje, że wartość jest dostępna.Gdy zdarzenie jest ustawiona, detektor zadania ukończone i 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 Bloki komunikatów asynchronicznych.

cancel_after_timeout Funkcja opiera się na complete_after funkcji, aby anulować zadania, jeśli to zadanie nie zostało ukończone przed danym limitu czasu.cancel_after_timeout Funkcja tworzy dwa zadania.Pierwsze zadanie oznacza sukces i kończy się 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 uruchamiane po ukończeniu zadania powodzeniu lub niepowodzeniu.Jeśli zadanie awarii zakończy się pierwszy, kontynuacji anuluje tokenu źródłowego 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 w zakresie [0, 100000] wiele razy.Operacja nie powiedzie się, jeśli nie zostanie zakończona w określonym terminie.count_primes Funkcja pokazuje sposób użycia cancel_after_timeout funkcji.To oblicza, ile liczb pierwszych w danym zakresie i nie powiedzie się, jeśli zadanie nie została zakończona w podanego czasu.wmain Wywołania funkcji count_primes funkcjonować wiele razy.Za każdym razem, połówki limit czasu.Program kończy działanie po operacji nie uzupełni w bieżącym limicie czasu.

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

Korzystając z tej techniki Aby anulować zadania z opóźnieniem, wszystkich nierozpoczętych zadań nie uruchamia się po ogólne zadanie zostało anulowane.Jednakże ważne jest dla dowolnego zadania długim odpowiada na anulowanie w sposób terminowy.W tym przykładzie count_primes wywołania metody concurrency::is_task_cancellation_requested i cancel_current_task funkcje odpowiada 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 a następnie wkleić go w projekcie programu Visual Studio lub wkleić go w pliku o nazwie zadanie delay.cpp , a następnie uruchomić następujące polecenie w oknie wiersza polecenia programu Visual Studio.

cl.exe /EHsc task-delay.cpp

Zobacz też

Informacje

task — Klasa (współbieżność środowiska wykonawczego)

cancellation_token_source — Klasa

cancellation_token — Klasa

task_completion_event — Klasa

is_task_cancellation_requested — Funkcja

cancel_current_task — Funkcja

interruption_point — Funkcja

timer — Klasa

call — Klasa

Koncepcje

Równoległość zadania (współbieżność środowiska wykonawczego)

Bloki komunikatów asynchronicznych

Anulowanie w PPL