共用方式為


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

本主題說明如何針對基本的樹狀結構撰寫搜尋演算法。

PPL 中的取消主題說明取消動作在平行模式程式庫中的角色。 比起用 concurrency::task_group::cancelconcurrency::structured_task_group::cancel 方法,用例外狀況處理來取消平行工作比較沒有效率。 不過,一種適合使用例外狀況處理來取消工作的案例是,當您呼叫會使用工作或平行演算法但未提供可取消之 task_groupstructured_task_group 物件的協力廠商程式庫。

範例

下列範例顯示基本的 tree 型別,這個型別包含一個資料項目和一份子節點清單。 下列各節顯示 for_all 方法的主體,該方法會以遞迴方式在每個子節點上執行工作函式。

// A simple tree structure that has multiple child nodes. 
template <typename T>
class tree
{
public:
   explicit tree(T data)
      : _data(data)
   {
   }

   // Retrieves the data element for the node. 
   T get_data() const
   {
      return _data;
   }

   // Adds a child node to the tree. 
   void add_child(tree& child)
   {
      _children.push_back(child);
   }

   // Performs the given work function on the data element of the tree and 
   // on each child. 
   template<class Function>
   void for_all(Function& action);

private:
   // The data for this node.
   T _data;
   // The child nodes.
   list<tree> _children;
};

下列範例顯示 for_all 方法。 這個方法會使用 concurrency::parallel_for_each 演算法,以平行方式在樹狀結構的每個節點上執行工作函式。

// Performs the given work function on the data element of the tree and 
// on each child. 
template<class Function>
void for_all(Function& action)
{
   // Perform the action on each child.
   parallel_for_each(begin(_children), end(_children), [&](tree& child) {
      child.for_all(action);
   });

   // Perform the action on this node.
   action(*this);
}

下列範例顯示 search_for_value 函式,這個函式會在提供的 tree 物件中搜尋值。 這個函式會傳遞工作函式給 for_all 方法,該函式會在發現有樹狀節點包含所提供的值時擲回例外狀況。

假設 tree 類別是由協力廠商程式庫所提供,而且您無法變更它。 在此情況下,適合使用例外狀況處理,因為 for_all 方法未提供 task_groupstructured_task_group 物件給呼叫端。 因此,工作函式無法直接取消其父工作群組。

當您提供給工作群組的工作函式擲回例外狀況時,執行階段會停止工作群組中的所有工作 (包括任何子工作群組),並且捨棄任何尚未開始的工作。 search_for_value 函式會使用 try-catch 區塊來擷取例外狀況並將結果列印至主控台。

// Searches for a value in the provided tree object. 
template <typename T>
void search_for_value(tree<T>& t, int value)
{
   try
   {
      // Call the for_all method to search for a value. The work function 
      // throws an exception when it finds the value.
      t.for_all([value](const tree<T>& node) {
         if (node.get_data() == value)
         {
            throw &node;
         }
      });
   }
   catch (const tree<T>* node)
   {
      // A matching node was found. Print a message to the console.
      wstringstream ss;
      ss << L"Found a node with value " << value << L'.' << endl;
      wcout << ss.str();
      return;
   }

   // A matching node was not found. Print a message to the console.
   wstringstream ss;
   ss << L"Did not find node with value " << value << L'.' << endl;
   wcout << ss.str();   
}

下列範例會建立 tree 物件並以平行方式在其中搜尋數個值。 本主題稍後會說明 build_tree 函式。

int wmain()
{  
   // Build a tree that is four levels deep with the initial level  
   // having three children. The value of each node is a random number.
   mt19937 gen(38);
   tree<int> t = build_tree<int>(4, 3, [&gen]{ return gen()%100000; });

   // Search for a few values in the tree in parallel.
   parallel_invoke(
      [&t] { search_for_value(t, 86131); },
      [&t] { search_for_value(t, 17522); },
      [&t] { search_for_value(t, 32614); }
   );
}

這個範例會使用 concurrency::parallel_invoke 演算法以平行方式搜尋值。 如需這個演算法的詳細資訊,請參閱平行演算法

下列完整範例會使用例外狀況處理來搜尋基本樹狀結構中的值。

// task-tree-search.cpp 
// compile with: /EHsc
#include <ppl.h>
#include <list>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <random>

using namespace concurrency;
using namespace std;

// A simple tree structure that has multiple child nodes. 
template <typename T>
class tree
{
public:
   explicit tree(T data)
      : _data(data)
   {
   }

   // Retrieves the data element for the node. 
   T get_data() const
   {
      return _data;
   }

   // Adds a child node to the tree. 
   void add_child(tree& child)
   {
      _children.push_back(child);
   }

   // Performs the given work function on the data element of the tree and 
   // on each child. 
   template<class Function>
   void for_all(Function& action)
   {
      // Perform the action on each child.
      parallel_for_each(begin(_children), end(_children), [&](tree& child) {
         child.for_all(action);
      });

      // Perform the action on this node.
      action(*this);
   }

private:
   // The data for this node.
   T _data;
   // The child nodes.
   list<tree> _children;
};

// Builds a tree with the given depth.  
// Each node of the tree is initialized with the provided generator function. 
// Each level of the tree has one more child than the previous level. 
template <typename T, class Generator>
tree<T> build_tree(int depth, int child_count, Generator& g)
{
   // Create the tree node.
   tree<T> t(g());

   // Add children. 
   if (depth > 0)
   {
      for(int i = 0; i < child_count; ++i)
      {
         t.add_child(build_tree<T>(depth - 1, child_count + 1, g));
      }
   }

   return t;
}

// Searches for a value in the provided tree object. 
template <typename T>
void search_for_value(tree<T>& t, int value)
{
   try
   {
      // Call the for_all method to search for a value. The work function 
      // throws an exception when it finds the value.
      t.for_all([value](const tree<T>& node) {
         if (node.get_data() == value)
         {
            throw &node;
         }
      });
   }
   catch (const tree<T>* node)
   {
      // A matching node was found. Print a message to the console.
      wstringstream ss;
      ss << L"Found a node with value " << value << L'.' << endl;
      wcout << ss.str();
      return;
   }

   // A matching node was not found. Print a message to the console.
   wstringstream ss;
   ss << L"Did not find node with value " << value << L'.' << endl;
   wcout << ss.str();   
}

int wmain()
{  
   // Build a tree that is four levels deep with the initial level  
   // having three children. The value of each node is a random number.
   mt19937 gen(38);
   tree<int> t = build_tree<int>(4, 3, [&gen]{ return gen()%100000; });

   // Search for a few values in the tree in parallel.
   parallel_invoke(
      [&t] { search_for_value(t, 86131); },
      [&t] { search_for_value(t, 17522); },
      [&t] { search_for_value(t, 32614); }
   );
}

這個範例 (Example) 產生下列範例 (Sample) 輸出。

  

編譯程式碼

請複製範例程式碼,並將它貼在 Visual Studio 專案中,或貼在名為 task-tree-search.cpp 的檔案中,然後在 Visual Studio 的 [命令提示字元] 視窗中執行下列命令。

cl.exe /EHsc task-tree-search.cpp

請參閱

參考

task_group 類別

structured_task_group 類別

parallel_for_each 函式

概念

PPL 中的取消

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

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

平行演算法