如何:使用例外狀況處理來中斷平行迴圈
本主題說明如何撰寫基本樹狀結構的搜尋演算法。
「取消」主題說明平行模式連結庫中取消的角色。 使用例外狀況處理比使用並行處理::task_group::cancel 和 concurrency::structured_task_group::cancel 方法來取消平行工作的效率較低。 不過,當您呼叫使用工作或平行演算法但未提供 task_group
或 structured_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::p arallel_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_group
或 structured_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::p arallel_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); }
);
}
此範例會產生下列範例輸出。
Found a node with value 32614.
Found a node with value 86131.
Did not find node with value 17522.
編譯程式碼
複製範例程式代碼,並將其貼到 Visual Studio 專案中,或貼到名為 task-tree-search.cpp
的檔案中,然後在 Visual Studio 命令提示字元視窗中執行下列命令。
cl.exe /EHsc task-tree-search.cpp
另請參閱
PPL 中的取消
例外狀況處理
工作平行處理原則
平行演算法
task_group 類別
structured_task_group 類別
parallel_for_each函式