共用方式為


PPL 中的取消

文件在平行模式程式庫 (PPL) 中說明取消的角色、如何取消平行工作,以及如何判斷平行工作取消時

注意事項注意事項

執行階段使用例外狀況處理來實作取消作業。請不要攔截或處理程式碼中的這些例外狀況。此外,建議您函式主體中為您的工作撰寫無例外狀況之虞的程式碼。例如,當工作的主體中擲回例外狀況時,您可以使用「資源擷取為初始設定」(Resource Acquisition Is Initialization,RAII) 模式確保正確處理資源。如需使用 RAII 模式在可取消的工作中清除資源的完整範例,請參閱逐步解說:從使用者介面執行緒中移除工作

金鑰

在文件中。

  • 平行工作樹狀結構

  • 取消平行工作

    • 使用取消語彙基元的取消平行工作

    • 使用取消方法來取消平行工作

    • 使用例外狀況取消平行工作

  • 取消平行演算法

  • 不使用取消的時機

平行工作樹狀結構

PPL 以工作和工作群組來管理更精細的工作和計算。您可以將工作群組巢狀化,以形成平行工作的「樹狀結構」(Tree)。下圖顯示平行工作樹狀結構。在圖中, tg1tg2 表示工作群組, t1t2t3t4t5 表示工作群組中執行的工作。

平行工作樹狀結構

下列範例顯示在圖例中建立樹狀結構時所需的程式碼。在此範例中, tg1tg2concurrency::structured_task_group 物件; t1t2t3t4t5concurrency::task_handle 物件。

// task-tree.cpp
// compile with: /c /EHsc
#include <ppl.h>
#include <sstream>
#include <iostream>
#include <sstream>

using namespace concurrency;
using namespace std;

void create_task_tree()
{   
   // Create a task group that serves as the root of the tree.
   structured_task_group tg1;

   // Create a task that contains a nested task group.
   auto t1 = make_task([&] {
      structured_task_group tg2;

      // Create a child task.
      auto t4 = make_task([&] {
         // TODO: Perform work here.
      });

      // Create a child task.
      auto t5 = make_task([&] {
         // TODO: Perform work here.
      });

      // Run the child tasks and wait for them to finish.
      tg2.run(t4);
      tg2.run(t5);
      tg2.wait();
   });

   // Create a child task.
   auto t2 = make_task([&] {
      // TODO: Perform work here.
   });

   // Create a child task.
   auto t3 = make_task([&] {
      // TODO: Perform work here.
   });

   // Run the child tasks and wait for them to finish.
   tg1.run(t1);
   tg1.run(t2);
   tg1.run(t3);
   tg1.wait();   
}

您也可以使用 concurrency::task_group 類別建立一個類似的工作樹狀結構。concurrency::task 類別也支援工作樹狀結構的概念。不過, task 樹狀結構是相依樹狀結構。在 task 樹狀結構,未來的工作在目前工作之後。在工作群組中,內部工作在外部工作之前完成。如需工作和工作群組之間差異的詳細資訊,請參閱 工作平行處理原則 (並行執行階段)

[]上述

取消平行工作

有幾種方式取消平行工作。好的方式是使用取消語彙基元。工作群組也支援 concurrency::task_group::cancel 方法和 concurrency::structured_task_group::cancel 方法。最終的方法將會擲回在工作的工作函式主體中擲回例外狀況。您所選擇的方法,了解無論移除不會立即發生。雖然新的工作不會啟動,如果工作或工作群組取消,作用中工作必須偵測和回應取消作業。

如需取消平行工作的詳細範例,請參閱 逐步解說:使用工作和 XML HTTP 要求 (IXHR2) 連線HOW TO:使用取消來中斷平行迴圈HOW TO:使用例外狀況處理來中斷平行迴圈

Dd984117.collapse_all(zh-tw,VS.110).gif使用取消語彙基元的取消平行工作

tasktask_groupstructured_task_group 類別使用取消語彙基元支援取消作業。PPL 提供這個定義 concurrency::cancellation_token_sourceconcurrency::cancellation_token 類別。當您使用取消語彙基元來取消工作時,執行階段不會啟動訂閱這個語彙基元的新工作。工作已經作用中監視其取消語彙基元和停止,則可以。

若要啟始取消,請呼叫 concurrency::cancellation_token_source::cancel 方法。您回應取消使用下列方法:

下列範例顯示工作取消的第一個基本模式。工作主體偶爾檢查在迴圈內移除。

// task-basic-cancellation.cpp
// compile with: /EHsc
#include <ppltasks.h>
#include <iostream>
#include <sstream>

using namespace concurrency;
using namespace std;

bool do_work()
{
    // Simulate work.
    wcout << L"Performing work..." << endl;
    wait(250);
    return true;
}

int wmain()
{
    cancellation_token_source cts;
    auto token = cts.get_token();

    wcout << L"Creating task..." << endl;

    // Create a task that performs work until it is canceled.
    auto t = create_task([]
    {
        bool moreToDo = true;
        while (moreToDo)
        {
            // Check for cancellation.
            if (is_task_cancellation_requested())
            {
                // TODO: Perform any necessary cleanup here...

                // Cancel the current task.
                cancel_current_task();
            }
            else 
            {
                // Perform work.
                moreToDo = do_work();
            }
        }
    }, token);

    // Wait for one second and then cancel the task.
    wait(1000);

    wcout << L"Canceling task..." << endl;
    cts.cancel();

    // Wait for the task to cancel.
    wcout << L"Waiting for task to complete..." << endl;
    t.wait();

    wcout << L"Done." << endl;
}

/* Sample output:
    Creating task...
    Performing work...
    Performing work...
    Performing work...
    Performing work...
    Canceling task...
    Waiting for task to complete...
    Done.
*/

cancel_current_task 函式擲回,因此,您不需要從目前迴圈或函式明確地傳回。

提示提示

或者,您可以呼叫 concurrency::interruption_point 函式來取代 is_task_cancellation_requestedcancel_current_task

,當您回應取消作業,因為它轉換工作與已取消的狀態時,會呼叫 cancel_current_task 很重要。如果您先前傳回而不是呼叫 cancel_current_task,與已完成狀態的作業轉換和所有數值的繼續執行。

注意事項警告

不要擲回的程式碼中 task_canceled 。呼叫 cancel_current_task

當處於取消狀態的工作完成, concurrency::task::get 方法擲回 concurrency::task_canceled。(相反地, concurrency::task::wait 傳回 task_status::canceled ,而且不會擲回)。下列範例說明如何以工作為基礎的接續的行為。,即使前項工作取消時,工作說明繼續一定要呼叫。

// task-canceled.cpp
// compile with: /EHsc
#include <ppltasks.h>
#include <iostream>

using namespace concurrency;
using namespace std;

int wmain()
{
    auto t1 = create_task([]() -> int
    {
        // Cancel the task.
        cancel_current_task();
    });

    // Create a continuation that retrieves the value from the previous.
    auto t2 = t1.then([](task<int> t)
    {
        try
        {
            int n = t.get();
            wcout << L"The previous task returned " << n << L'.' << endl;
        }
        catch (const task_canceled& e)
        {
            wcout << L"The previous task was canceled." << endl;
        }
    });

    // Wait for all tasks to complete.
    t2.wait();
}
/* Output:
    The previous task was canceled.
*/

由於數值的接續繼承其前項工作語彙基元,除非用明確建立語彙基元之後,繼續立即進入已取消的狀態,即使前項工作仍在執行。因此,根據前項工作所擲回的任何例外狀況,取消不會散佈至接續工作之後。移除一律會覆寫前項工作的狀態。下列範例類似於前一個動畫的設定,但是,說明數值的接續的行為。

auto t1 = create_task([]() -> int
{
    // Cancel the task.
    cancel_current_task();
});

// Create a continuation that retrieves the value from the previous.
auto t2 = t1.then([](int n)
{
    wcout << L"The previous task returned " << n << L'.' << endl;
});

try
{
    // Wait for all tasks to complete.
    t2.get();
}
catch (const task_canceled& e)
{
    wcout << L"The task was canceled." << endl;
}
/* Output:
    The task was canceled.
*/
注意事項警告

如果您不將取消語彙基元傳遞至 task 建構函式或 concurrency::create_task 函式,該工作不會被取消。此外,您必須傳遞相同的取消語彙基元加入至另一項工作主體所建立) 所有巢狀工作 (也就是工作的建構函式同時移除所有工作。

,當取消語彙基元取消時,您可能會想要執行任意程式碼。例如,在中,如果使用者在使用者介面中選取一 [取消] 按鈕則會取消作業,您可以停用該按鈕,直到使用者啟動另一個作業。下列範例顯示如何使用 concurrency::cancellation_token::register_callback 方法註冊執行的回呼函式,當取消語彙基元取消。

// task-cancellation-callback.cpp
// compile with: /EHsc
#include <ppltasks.h>
#include <iostream>

using namespace concurrency;
using namespace std;

int wmain()
{
    cancellation_token_source cts;
    auto token = cts.get_token();

    // An event that is set in the cancellation callback.
    event e;

    cancellation_token_registration cookie;
    cookie = token.register_callback([&e, token, &cookie]()
    {
        wcout << L"In cancellation callback..." << endl;
        e.set();

        // Although not required, demonstrate how to unregister 
        // the callback.
        token.deregister_callback(cookie);
    });

    wcout << L"Creating task..." << endl;

    // Create a task that waits to be canceled.
    auto t = create_task([&e]
    {
        e.wait();
    }, token);

    // Cancel the task.
    wcout << L"Canceling task..." << endl;
    cts.cancel();

    // Wait for the task to cancel.
    t.wait();

    wcout << L"Done." << endl;
}
/* Sample output:
    Creating task...
    Canceling task...
    In cancellation callback...
    Done.
*/

文件 工作平行處理原則 (並行執行階段) 說明以和的值以工作為基礎的接續之間的差異。如果您不提供對接續工作的 cancellation_token 物件,繼續下列方式繼承自前項工作的取消語彙基元:

  • 數值的接續永遠會繼承前項工作的取消語彙基元。

  • 以工作為基礎的接續永遠不繼承前項工作的取消語彙基元。唯一的方式讓工作說明取消接續會明確將取消語彙基元。

這些行為並不會影響已發生錯誤的工作 (也就是擲回例外狀況) 的。在這種情況下,數值的接續取消,以工作為基礎的接續未取消。

注意事項警告

在另一個工作 (換句話說,工作 (巢狀工作) 建立不是繼承自父工作的取消語彙基元。只有數值的接續繼承前項工作取消語彙基元。

提示提示

請使用 concurrency::cancellation_token::none 方法,當您呼叫接受 cancellation_token 物件的建構函式或函式時,若您不要為取消作業的。

您也可以提供取消語彙基元。 task_groupstructured_task_group 物件的建構函式。這個的一個重要概念是子工作群組會繼承這個取消語彙基元。如需示範這個概念使用 concurrency::run_with_cancellation_token 函式提供執行呼叫 parallel_for的範例,請參閱 取消平行演算法 之後在文件。

[]上述

Dd984117.collapse_all(zh-tw,VS.110).gif取消語彙基元和工作撰寫

concurrency::when_allconcurrency::when_any 函式可協助您撰寫多項工作實作常見的模式。本節將說明這些函式如何使用取消語彙基元一起使用。

當您提供取消語彙基元將任一 when_allwhen_any 函式,該函式會移除,只有當該取消語彙基元取消,或其中一個會復原狀態的參與者工作完成或擲回例外狀況。

when_all 函式繼承自撰寫整個作業之每項工作的取消語彙基元,所以提供取消語彙基元重新命名時。從 when_all 傳回的工作取消時,這些語彙基元中的任何一個取消和工作尚未啟動或執行中至少有一個參與者。類似的行為,就會發生這個錯誤的其中一個工作擲回例外狀況 when_all –從傳回的工作會立即移除具有該例外狀況。

執行階段選擇 when_any 從函式傳回的工作取消語彙基元,當某項工作完成時。如果參與者工作都已完成狀態尚未完成,而且中的一個或多個工作擲回例外狀況,擲回例外狀況的其中一項工作選取完成 when_any 及其語彙基元選取做為最終工作的語彙基元。如果有一個以上的工作會在已完成狀態完成,從 when_any 在已完成狀態的工作完成傳回的工作。執行階段嘗試挑選語彙基元不會在完成時取消的工作完成,以便 when_any 傳回的工作不會立即取消,即使其他執行緒的工作也會在稍後。

[]上述

Dd984117.collapse_all(zh-tw,VS.110).gif使用取消方法來取消平行工作

concurrency::task_group::cancelconcurrency::structured_task_group::cancel 方法會設定一個工作群組設為已取消的狀態。在您呼叫 cancel 之後,工作群組即不會啟動未來的工作。cancel 方法可由多項子工作來呼叫。已取消的工作會導致 concurrency::task_group::waitconcurrency::structured_task_group::wait 方法傳回 concurrency::canceled

在工作群組遭到取消時,執行階段中每個從子工作發出的呼叫將可觸發「中斷點」(Interruption Point),而使執行階段擲回和攔截內部例外狀況類型,以取消作用中的工作。並行執行階段並未定義特定的中斷點;中斷點可透過執行階段中的任何呼叫來產生。執行階段必須處理它所擲回的例外狀況,以執行取消作業。因此,請不要處理工作主體中的未知例外狀況。

如果子工作正在執行耗時的作業,且未在執行階段中發出呼叫,則必須定期檢查取消的狀態,並適時地結束作業。下列範例說明一種判斷工作於何時取消的方式。工作 t4 會在錯誤發生時取消父工作群組。工作 t5 偶爾會呼叫 structured_task_group::is_canceling 方法,以檢查取消的狀態。如果父工作群組已取消,工作 t5 顯示訊息,並結束作業。

structured_task_group tg2;

// Create a child task.
auto t4 = make_task([&] {
   // Perform work in a loop.
   for (int i = 0; i < 1000; ++i)
   {
      // Call a function to perform work.
      // If the work function fails, cancel the parent task
      // and break from the loop.
      bool succeeded = work(i);
      if (!succeeded)
      {
         tg2.cancel();
         break;
      }
   }
});

// Create a child task.
auto t5 = make_task([&] {
   // Perform work in a loop.
   for (int i = 0; i < 1000; ++i)
   {
      // To reduce overhead, occasionally check for 
      // cancelation.
      if ((i%100) == 0)
      {
         if (tg2.is_canceling())
         {
            wcout << L"The task was canceled." << endl;
            break;
         }
      }

      // TODO: Perform work here.
   }
});

// Run the child tasks and wait for them to finish.
tg2.run(t4);
tg2.run(t5);
tg2.wait();

此範例會在工作迴圈每反覆執行 100 次時,檢查取消的狀態。您檢查取消狀態的頻率,取決於您所執行的工作量,以及您的工作必須多快回應取消要求。

如果您無法存取父工作群組物件的,請呼叫 concurrency::is_current_task_group_canceling 函式以判斷父工作群組是否已取消。

cancel 方法只會影響子工作。例如,如果您在平行工作樹狀結構的圖例中取消了工作群組 tg1,則樹狀結構中的所有工作 (t1t2t3t4t5) 都會受到影響。如果您取消了巢狀工作群組 tg2,則只有 t4t5 工作會受到影響。

當您呼叫 cancel 方法時,所有的子工作群組也都會被取消。但是,取消並不會影響平行工作樹狀結構中的工作群組的任何父代。下列範例透過建置平行工作樹狀結構圖例加以說明。

其中的第一個範例會建立工作 t4 的工作函式,此工作是工作群組 tg2 的子系。此工作函式會以迴圈呼叫函式 work。如果 work 的任何呼叫失敗,工作即會取消其父工作群組。這會導致工作群組 tg2 進入已取消的狀態,但並不會取消工作群組 tg1

auto t4 = make_task([&] {
   // Perform work in a loop.
   for (int i = 0; i < 1000; ++i)
   {
      // Call a function to perform work.
      // If the work function fails, cancel the parent task
      // and break from the loop.
      bool succeeded = work(i);
      if (!succeeded)
      {
         tg2.cancel();
         break;
      }
   }         
});

第二個範例與第一個類似,不同之處在於工作會取消工作群組 tg1。這會影響樹狀結構中的所有工作 (t1t2t3t4t5)。

auto t4 = make_task([&] {
   // Perform work in a loop.
   for (int i = 0; i < 1000; ++i)
   {
      // Call a function to perform work.
      // If the work function fails, cancel all tasks in the tree.
      bool succeeded = work(i);
      if (!succeeded)
      {
         tg1.cancel();
         break;
      }
   }   
});

structured_task_group 類別不具備執行緒安全。因此,若有子工作呼叫其父 structured_task_group 物件的方法,將會產生未指定的行為。此規則的例外是 structured_task_group::cancelconcurrency::structured_task_group::is_canceling 方法。子工作可以呼叫這些方法以取消父工作群組和檢查取消的。

注意事項警告

雖然您可以使用取消語彙基元取消工作群組執行以 task 物件的子系的工作,您不能使用 task_group::cancelstructured_task_group::cancel 方法移除工作群組中執行的 task 物件。

[]上述

Dd984117.collapse_all(zh-tw,VS.110).gif使用例外狀況取消平行工作

使用取消語彙基元和 cancel 方法比例外處理有效在取消平行工作樹狀結構。取消語彙基元和 cancel 方法取消的工作和所有子工作都以由上至下的方式。相反地,例外狀況處理則會由下而上執行,且必須在例外狀況往上傳播時個別取消每一個子工作群組。並行執行階段的例外狀況處理主題說明並行執行階段如何使用例外狀況發出錯誤。但並非所有的例外狀況都表示有錯誤。例如,在中,在找到結果時,搜尋演算法可能會移除其相關聯的工作。但如前所述,相較於使用 cancel 方法取消平行工作,處理例外狀況顯得較沒效率。

注意事項警告

建議您使用例外狀況取消平行工作,也只會在必要時。取消語彙基元和工作群組 cancel 方法是更有效率且更不容易出錯。

當您在傳遞至工作群組的工作函式主體中擲回例外狀況時,執行階段會儲存該例外狀況,並將其封送處理至等候工作群組完成的內容。與使用 cancel 方法時相同,執行階段會捨棄任何尚未啟動的工作,並且不會接受新的工作。

第三個範例與第二個類似,不同之處在於工作 t4 會擲回例外狀況,以取消工作群組 tg2。這個範例會使用 try-catch 區塊,在工作群組 tg2 等候其子工作完成時檢查取消的狀態。與第一個範例相同,這會使工作群組 tg2 進入已取消的狀態,但並不會取消工作群組 tg1

structured_task_group tg2;

// Create a child task.      
auto t4 = make_task([&] {
   // Perform work in a loop.
   for (int i = 0; i < 1000; ++i)
   {
      // Call a function to perform work.
      // If the work function fails, throw an exception to 
      // cancel the parent task.
      bool succeeded = work(i);
      if (!succeeded)
      {
         throw exception("The task failed");
      }
   }         
});

// Create a child task.
auto t5 = make_task([&] {
   // TODO: Perform work here.
});

// Run the child tasks.
tg2.run(t4);
tg2.run(t5);

// Wait for the tasks to finish. The runtime marshals any exception
// that occurs to the call to wait.
try
{
   tg2.wait();
}
catch (const exception& e)
{
   wcout << e.what() << endl;
}

第四個範例會使用例外狀況處理,將整個工作樹狀結構取消。此範例會在工作群組 tg1 等候其子工作完成時攔截例外狀況,而不會在工作群組 tg2 等候其子工作執行時進行攔截。如同第二個範例,這會使樹狀結構中的兩個工作群組 tg1tg2 都進入已取消的狀態。

// Run the child tasks.
tg1.run(t1);
tg1.run(t2);
tg1.run(t3);   

// Wait for the tasks to finish. The runtime marshals any exception
// that occurs to the call to wait.
try
{
   tg1.wait();
}
catch (const exception& e)
{
   wcout << e.what() << endl;
}

由於 task_group::waitstructured_task_group::wait 方法會在子工作擲回例外狀況時擲回,因此您不會收到它們所傳回的值。

[]上述

取消平行演算法

PPL 中的平行演算法,例如, parallel_for,在工作群組中的組建。因此,您可以使用許多相同的技術來取消平行演算法。

下列範例說明數種可取消平行演算法的方式。

下列範例會使用 run_with_cancellation_token 函式呼叫 parallel_for 演算法。run_with_cancellation_token 函式接受取消語彙基元做為引數而呼叫同步處理時所提供的工作函式。因為平行演算法是建立在工作中,它們會繼承父工作的取消語彙基元。因此, parallel_for 可以回應取消作業。

// cancel-parallel-for.cpp
// compile with: /EHsc
#include <ppltasks.h>
#include <iostream>
#include <sstream>

using namespace concurrency;
using namespace std;

int wmain()
{
    // Call parallel_for in the context of a cancellation token.
    cancellation_token_source cts;
    run_with_cancellation_token([&cts]() 
    {
        // Print values to the console in parallel.
        parallel_for(0, 20, [&cts](int n)
        {
            // For demonstration, cancel the overall operation 
            // when n equals 11.
            if (n == 11)
            {
                cts.cancel();
            }
            // Otherwise, print the value.
            else
            {
                wstringstream ss;
                ss << n << endl;
                wcout << ss.str();
            }
        });
    }, cts.get_token());
}
/* Sample output:
    15
    16
    17
    10
    0
    18
    5
*/

下列範例會使用 concurrency::structured_task_group::run_and_wait 方法呼叫 parallel_for 演算法。structured_task_group::run_and_wait 方法會等候所提供的工作完成。structured_task_group 物件可讓工作函式取消工作。

// To enable cancelation, call parallel_for in a task group.
structured_task_group tg;

task_group_status status = tg.run_and_wait([&] {
   parallel_for(0, 100, [&](int i) {
      // Cancel the task when i is 50.
      if (i == 50)
      {
         tg.cancel();
      }
      else
      {
         // TODO: Perform work here.
      }
   });
});

// Print the task group status.
wcout << L"The task group status is: ";
switch (status)
{
case not_complete:
   wcout << L"not complete." << endl;
   break;
case completed:
   wcout << L"completed." << endl;
   break;
case canceled:
   wcout << L"canceled." << endl;
   break;
default:
   wcout << L"unknown." << endl;
   break;
}

這個範例產生下列輸出。

The task group status is: canceled.

下列範例會使用例外狀況處理來取消 parallel_for 迴圈。執行階段會將例外狀況封送處理至呼叫的內容。

try
{
   parallel_for(0, 100, [&](int i) {
      // Throw an exception to cancel the task when i is 50.
      if (i == 50)
      {
         throw i;
      }
      else
      {
         // TODO: Perform work here.
      }
   });
}
catch (int n)
{
   wcout << L"Caught " << n << endl;
}

這個範例產生下列輸出。

Caught 50

下列範例會使用布林值旗標協調 parallel_for 迴圈中的取消。由於此範例未使用 cancel 方法或例外狀況處理來取消整體的工作集,所以每項工作都會執行。因此,這項技術的計算額外負荷可能會高於取消機制。

// Create a Boolean flag to coordinate cancelation.
bool canceled = false;

parallel_for(0, 100, [&](int i) {
   // For illustration, set the flag to cancel the task when i is 50.
   if (i == 50)
   {
      canceled = true;
   }

   // Perform work if the task is not canceled.
   if (!canceled)
   {
      // TODO: Perform work here.
   }
});

每個取消方法都有其優缺點。請選擇符合您特定需求的方法。

[]上述

不使用取消的時機

如果相關工作的每個群組成員皆可適時結束,則適合使用取消。但在某些情況下,取消可能不適用於您的應用程式。例如,由於取消工作是合作式作業,因此如果有任何個別工作遭到封鎖,整體的工作集即不會取消。例如,如果某項工作尚未啟動,但它將另一個作用中工作解除封鎖,則在工作群組取消時,此工作將不會啟動。這可能會造成應用程式中發生死結。另一個不適合使用取消的例子是當工作已取消,但其子工作正在執行重要的作業,例如釋放資源。因為父工作取消時,整組工作都會被取消,所以不會執行該作業。如需說明這點的範例,請參閱<平行模式程式庫中的最佳作法>主題的Understand how Cancellation and Exception Handling Affect Object Destruction一節。

[]上述

相關主題

標題

描述

HOW TO:使用取消來中斷平行迴圈

說明如何使用取消來實作平行搜尋演算法。

HOW TO:使用例外狀況處理來中斷平行迴圈

示範如何使用 task_group 類別來撰寫基本樹狀結構的搜尋演算法。

並行執行階段的例外狀況處理

說明執行階段如何處理由工作群組、輕量型工作和非同步代理程式所擲回的例外狀況,以及如何回應您應用程式中的例外狀況。

工作平行處理原則 (並行執行階段)

說明工作與工作群組之間的相關性,以及如何在您的應用程式中使用非結構化與結構化的工作。

平行演算法

說明可對資料集合執行並行工作的平行演算法

平行模式程式庫 (PPL)

提供平行模式程式庫的概觀。

參考資料

task 類別 (並行執行階段)

cancellation_token_source 類別

cancellation_token 類別

task_group 類別

structured_task_group 類別

parallel_for 函式