Sdílet prostřednictvím


Postupy: Přerušení paralelní smyčky pomocí zpracování výjimek

Toto téma ukazuje, jak psát vyhledávací algoritmus pro základní stromové struktury.

Téma Zrušení v knihovně PPL vysvětluje roli zrušení v knihovně paralelní vzorky.Použití zpracování výjimek je méně efektivní způsob, jak zrušit paralelní práce než použití concurrency::task_group::cancel a concurrency::structured_task_group::cancel metody.Nicméně jeden scénář, kde je vhodné použít zpracování výjimek pro zrušení práce je při volání do jiných knihoven, které používá úkoly nebo paralelní algoritmy, ale neposkytuje task_group nebo structured_task_group objekt, který chcete zrušit.

Příklad

Následující příklad zobrazuje základní tree typ, který obsahuje prvek dat a v seznamu podřízené uzly.Následující část popisuje těla for_all metoda, která opakovaně provádí každý podřízený uzel pracovní funkce.

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

Následující příklad ukazuje for_all metody.Používá concurrency::parallel_for_each algoritmus pro každý uzel stromu paralelně provádět pracovní funkce.

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

Následující příklad ukazuje search_for_value funkci, která vyhledá danou hodnotu v poskytované tree objektu.Tato funkce předává for_all metoda a pracovní funkce, která vyvolá výjimku, pokud nalezne uzel stromu, který obsahuje zadanou hodnotou.

Předpokládejme, že tree třídy je k dispozici v knihovně třetí strany, a nelze jej upravovat.V tomto případě je vhodné použít zpracování výjimek protože for_all metoda neposkytuje task_group nebo structured_task_group objekt volající.Pracovní funkce tedy nelze přímo zrušit nadřazenou skupinu úloh.

Při práci funkce poskytující skupiny úloh vyvolá výjimku, modul runtime zastaví všechny úkoly, které jsou ve skupině úloh (včetně všech podřízených skupin úloh) a zahodí dosud nezahájené úkoly.search_for_value Funkce používá try-catch blok zachytit výjimku a tisknout výsledek do konzoly.

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

Následující příklad vytvoří tree objektu a hledá více hodnot současně.build_tree Funkce je uveden dále v tomto tématu.

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

V tomto příkladu concurrency::parallel_invoke algoritmus pro hledání hodnot paralelně.Další informace o tento algoritmus naleznete v tématu Paralelní algoritmy.

Kompletní příklad používá zpracování výjimek k vyhledání hodnot v základní stromové struktury.

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

Tento příklad vytvoří následující vzorový výstup.

  

Probíhá kompilace kódu

Zkopírovat ukázkový kód a vložit jej do projektu sady Visual Studio nebo vložit do souboru s názvem úkol strom search.cpp a potom spusťte následující příkaz v okně Příkazový řádek Visual Studio.

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

Viz také

Referenční dokumentace

task_group – třída

structured_task_group – třída

parallel_for_each – funkce

Koncepty

Zrušení v knihovně PPL

Zpracování výjimek v Concurrency Runtime

Funkční paralelismus (Concurrency Runtime)

Paralelní algoritmy