Sdílet prostřednictvím


Jak: použití zpracování přestávku na paralelní smyčku z výjimek

Toto téma ukazuje, jak napsat algoritmus vyhledávání pro základní stromové struktury.

Téma Zrušení v PPL vysvětluje jakou roli zrušení v Parallel Library 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 metod.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 knihovny výrobců, 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 seznam podřízených uzlů.Následující část popisuje těla for_all metodu, která opakovaně plní funkci práce na každý podřízený uzel.

// 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 metoda.Používá concurrency::parallel_for_each algoritmu v každém uzlu 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 funkce, která vyhledá hodnotu v poskytované tree objektu.Tato funkce předává for_all metoda a pracovní funkce, která se vyvolá, když najde uzel stromu, která obsahuje zadaná hodnota.

Předpokládejme, že tree knihovny výrobců poskytuje třídy a nelze jej upravovat.V takovém případě je vhodné použít zpracování výjimek protože for_all metoda neposkytuje task_group nebo structured_task_group objekt k volajícímu.Funkce práce tedy nelze přímo zrušit nadřazenou skupinu úloh.

Při práci funkce, která poskytují ke skupině úloh vyvolá výjimku, modul runtime zastaví všechny úkoly, které jsou ve skupině úloh (včetně všech podřízených skupin úkolů) a zahodí všechny úkoly, které dosud nebyly zahájeny.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á několik hodnot paralelně.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 algoritmu 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í výstup.

  
  
  

Probíhá kompilace kódu

Ukázkový kód zkopírujte a vložte do projektu aplikace Visual Studio nebo vložte do souboru s názvem úloh stromu search.cpp a potom spusťte následující příkaz v okně Příkazový řádek sady Visual Studio.

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

Viz také

Referenční dokumentace

Třída task_group

Třída structured_task_group

parallel_for_each funkce

Koncepty

Zrušení v PPL

Zpracování výjimek v souběžném běhu

Úkol rovnoběžnosti (souběžnosti Runtime)

Paralelní algoritmy