Freigeben über


Gewusst wie: Erstellen einer Aufgabe, die nach einer Verzögerung abgeschlossen wird

Dieses Beispiel zeigt, wie concurrency::task, concurrency::cancellation_token_source, concurrency::cancellation_token, concurrency::task_completion_event, concurrency::timer und concurrency::call-Klassen verwendet, um eine Aufgabe zu erstellen, die nach einer Verzögerung abgeschlossen hat.Sie können diese Methode verwenden, um Schleifen zu erstellen, die gelegentlich für Daten optimieren, die auftritt, Verzögerungsbehandlung der Benutzereingaben während einer vorgegebenen Zeit, u. a.

Beispiel

Im folgenden Beispiel werden die Funktionen complete_after und cancel_after_timeout dargestellt.Die complete_after-Funktion erstellt ein task-Objekt, das die angegebene Verzögerung nach Abschluss.Sie verwendet ein timer-Objekt und ein call-Objekt, um ein Objekt festzulegen task_completion_event nachdem die angegebene Verzögerung.Mithilfe der task_completion_event-Klasse verwenden, können Sie eine Aufgabe definieren, die abgeschlossen wird, nachdem ein Thread oder eine andere Aufgabe signalisiert, dass ein Wert verfügbar ist.Wenn das Ereignis festgelegt wird, schließen Listeneraufgaben ab und ihre Fortsetzungen geplant werden, um ausgeführt zu werden.

TippTipp

Weitere Informationen über die timer und call-Klassen, die Teil der Asynchronous Agents Library sind, finden Sie unter Asynchrone Nachrichtenblöcke.

Die cancel_after_timeout-Funktionsbuilds auf complete_after arbeiten, um eine Aufgabe abzubrechen, wenn diese Aufgabe nicht vor einem angegebenen Timeout beendet.Die cancel_after_timeout-Funktion erstellt zwei Aufgaben.Die erste Aufgabe gibt Erfolg an und bietet ab, nachdem die bereitgestellte Aufgabe abgeschlossen; die zweite Aufgabe gibt Fehler an und bietet nach dem angegebenen Timeout ab.Die cancel_after_timeout-Funktion erstellt eine Fortsetzungsaufgabe, die ausgeführt wird, wenn die Erfolgs- oder Fehleraufgabe abgeschlossen hat.Wenn die Fehleraufgabe zuerst abgeschlossen wurde, bricht die Fortsetzung die Tokenquelle ab, um die gesamte Aufgabe abzubrechen.

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

Im folgenden Beispiel wird die Anzahl der Primzahlen im Bereich [0, 100000] mehrmals.Der Vorgang schlägt fehl, wenn er nicht in einer Grenzzeit des bestimmten Zeitraum abgeschlossen hat.Die count_primes-Funktion veranschaulicht, wie die cancel_after_timeout-Funktion verwendet.Sie zählt die Anzahl der vorbereitet im angegebenen Bereich und fehlschlägt, wenn die Aufgabe nicht in der angegebenen Zeit abgeschlossen hat.Die wmain-Funktionsaufrufe die count_primes-Funktion mehrmals.Jedes Mal halbiert sie das Zeitlimit.Die Programmende, nachdem der Vorgang nicht im aktuellen Zeitlimits abgeschlossen hat.

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

Wenn Sie dieses Verfahren verwenden, Aufgaben abzubrechen, nachdem eine Verzögerung, keine unstarted Aufgaben nicht gestartet, nachdem die gesamte Aufgabe abgebrochen wird.Es ist jedoch wichtig, damit alle Aufgaben mit langer Laufzeit auf einen Abbruch rechtzeitig antworten.In diesem Beispiel count_primes die Methode die concurrency::is_task_cancellation_requested und cancel_current_task-Funktionen, um auf den Abbruch reagieren.(Alternativ, können Sie die concurrency::interruption_point-Funktion aufrufen).Weitere Informationen zu den Aufgabenabbruch, finden Sie unter Abbruch in der PPL.

Hier ist der vollständige Code für dieses Beispiel:

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

Kompilieren des Codes

So kompilieren Sie den Code, ihn kopieren und in einem Visual Studio-Projekt dann einfügen, oder fügen Sie ihn in eine Datei einfügen, die task-delay.cpp namens und dann den folgenden Befehl in einem Visual Studio-Eingabeaufforderungsfenster ausgeführt.

cl.exe /EHsc task-delay.cpp

Siehe auch

Referenz

task-Klasse (Concurrency Runtime)

cancellation_token_source-Klasse

cancellation_token-Klasse

task_completion_event-Klasse

is_task_cancellation_requested-Funktion

cancel_current_task-Funktion

interruption_point-Funktion

timer-Klasse

call-Klasse

Konzepte

Aufgabenparallelität (Concurrency Runtime)

Asynchrone Nachrichtenblöcke

Abbruch in der PPL