次の方法で共有


方法: 遅延後に完了するタスクを作成する

この例で concurrency::taskconcurrency::cancellation_token_sourceconcurrency::cancellation_tokenconcurrency::task_completion_eventconcurrency::timerと遅延の後で完了したタスクの作成に concurrency::call のクラスを使用する方法を示します。タイムアウト、スケジュール、処理に時間ユーザー入力の処理の遅延をなどのデータを定期的にポーリングするループをビルドするために、このメソッドを使用できます。

使用例

complete_after 関数および cancel_after_timeout 関数の例を次に示します。complete_after 関数は、指定した遅延完了した task のオブジェクトを作成します。これは timer のオブジェクトと task_completion_event のオブジェクトの設定に call のオブジェクトを、指定した遅延使用しました。task_completion_event のクラスを使用して、値が使用できることにスレッドまたは別のタスクがシグナルを送信し、タスクの完了を定義できます。イベントを設定すると、リスナーは完全にタスク、継続が実行されるようにスケジュールされます。

ヒントヒント

非同期エージェント ライブラリに含まれる timercall のクラスの詳細については、非同期メッセージ ブロックを参照してください。

complete_aftercancel_after_timeout 関数のビルドはそのタスクが指定されたタイムアウトの前に完了するタスクをキャンセルするために機能します。cancel_after_timeout の関数は 2 個のタスクを作成します。最初のタスクは、指定されたタスクが完了すると成功を表示し、終了します; 2 番目のタスクは失敗を示し、指定されたタイムアウトの後で完了します。cancel_after_timeout 関数が成功または失敗したタスクが完了すると実行される継続タスクを作成します。失敗したタスクが最初に実行される場合、継続はタスク全体をキャンセルするためにソースをキャンセル トークン。

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

次の例では、範囲[100000] 0、複数回の素数の数を計算します。操作は、特定の制限時間で完了する失敗します。count_primes 関数は cancel_after_timeout 関数を使用する方法を示します。これは、特定のスコープでタスクが、指定された時間内に完了する番号を発動を促し、失敗しました。カウントします。count_primes の関数を繰り返しがタイムアウト wmain の関数はを呼び出します。それぞれについて、制限時間を 2 倍にします。プログラムは、操作が現在の制限に完了した後で終わります。

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

タスク全体が[キャンセルと遅延が、unstarted 開始されていないタスクとタスクをキャンセルするには、この方法を使用します。ただし、キャンセルに応答タイムリーに、長時間実行されるタスクにとって重要です。この例では、count_primes のメソッドはキャンセルに応答するに concurrency::is_task_cancellation_requestedcancel_current_task 関数を呼び出します。(または、concurrency::interruption_point 関数を呼び出すことができます)。タスクのキャンセル処理の詳細については、PPL における取り消し処理を参照してください。

この例の完全なコード例を次に示します。:

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

コードのコンパイル

コードをコンパイル、配置、Visual Studio のプロジェクトに貼り付けるか、という名前 タスクdelay.cpp、Visual Studio コマンド プロンプト ウィンドウで次のコマンド実行ファイルに貼り付けます。

cl.exe /EHsc task-delay.cpp

参照

関連項目

task クラス (同時実行ランタイム)

cancellation_token_source クラス

cancellation_token クラス

task_completion_event クラス

is_task_cancellation_requested 関数

cancel_current_task 関数

interruption_point 関数

timer クラス

call クラス

概念

タスクの並列化 (同時実行ランタイム)

非同期メッセージ ブロック

PPL における取り消し処理