方法: 完了したタスクから選択する

この例では、Concurrency::choice クラスおよび Concurrency::join クラスを使用して、最初のタスクを選択して検索アルゴリズムを完了する方法について説明します。

使用例

次の例では 2 つの検索アルゴリズムを並列で実行し、最初のアルゴリズムを選択して完了します。 この例では、従業員の数値 ID と給与を格納する employee 型を定義します。 find_employee 関数は、指定された ID と指定された給与に該当する最初の従業員を検索します。 また、find_employee 関数は、指定された ID または指定された給与に該当する従業員がいない場合の処理も行います。 wmain 関数は、employee オブジェクトの配列を作成して複数の ID および給与の値を検索します。

次の例では、choice オブジェクトを使用して、次の事例を選択します。

  1. 指定された ID を持つ従業員。

  2. 指定された給与の従業員。

  3. 指定された ID または給与に該当しない従業員。

最初の 2 つの事例の場合、この例は Concurrency::single_assignment オブジェクトを使用して ID を保持し、別の single_assignment オブジェクトを使用して給与を保持します。 この例は、3 番目の事例に対して join オブジェクトを使用します。 join オブジェクトは、2 つの別の single_assignment オブジェクトで構成されます。1 つは、指定された ID を持つ従業員がいない事例に使用し、もう 1 つは指定された給与に該当する従業員がいない事例に使用します。 join オブジェクトは、その各メンバーがメッセージを受信したときにメッセージを送信します。 この例では、join オブジェクトは、指定された ID または給与に該当する従業員がいない場合にメッセージを送信します。

この例は、Concurrency::structured_task_group オブジェクトを使用して両方の検索アルゴリズムを並列で実行します。 各検索タスクが、指定された従業員が存在するかどうかを示す値を single_assignment オブジェクトの 1 つに書き込みます。 この例は、Concurrency::receive 関数を使用して、メッセージおよび結果を出力する switch ブロックを格納する最初のバッファーのインデックスを取得します。

// find-employee.cpp
// compile with: /EHsc
#include <agents.h>
#include <ppl.h>
#include <array>
#include <iostream>
#include <random>

using namespace Concurrency;
using namespace std;

// Contains information about an employee.
struct employee
{
   int id;
   float salary;
};

// Finds the first employee that has the provided id or salary.
template <typename T>
void find_employee(const T& employees, int id, float salary)
{
   // Holds the salary for the employee with the provided id.
   single_assignment<float> find_id_result;

   // Holds the id for the employee with the provided salary.
   single_assignment<int> find_salary_result;


   // Holds a message if no employee with the provided id exists.
   single_assignment<bool> id_not_found;

   // Holds a message if no employee with the provided salary exists.
   single_assignment<bool> salary_not_found;

   // Create a join object for the "not found" buffers.
   // This join object sends a message when both its members holds a message 
   // (in other words, no employee with the provided id or salary exists).
   auto not_found = make_join(&id_not_found, &salary_not_found);


   // Create a choice object to select among the following cases:
   // 1. An employee with the provided id exists.
   // 2. An employee with the provided salary exists.
   // 3. No employee with the provided id or salary exists.
   auto selector = make_choice(&find_id_result, &find_salary_result, &not_found);


   // Create a task that searches for the employee with the provided id.
   auto search_id_task = make_task([&]{
      auto result = find_if(employees.begin(), employees.end(), 
         [&](const employee& e) { return e.id == id; });
      if (result != employees.end())
      {
         // The id was found, send the salary to the result buffer.
         send(find_id_result, result->salary);
      }
      else
      {
         // The id was not found.
         send(id_not_found, true);
      }
   });

   // Create a task that searches for the employee with the provided salary.
   auto search_salary_task = make_task([&]{
      auto result = find_if(employees.begin(), employees.end(), 
         [&](const employee& e) { return e.salary == salary; });
      if (result != employees.end())
      {
         // The salary was found, send the id to the result buffer.
         send(find_salary_result, result->id);
      }
      else
      {
         // The salary was not found.
         send(salary_not_found, true);
      }
   });

   // Use a structured_task_group object to run both tasks.
   structured_task_group tasks;
   tasks.run(search_id_task);
   tasks.run(search_salary_task);

   wcout.setf(ios::fixed, ios::fixed);
   wcout.precision(2);

   // Receive the first object that holds a message and print a message.
   int index = receive(selector);
   switch (index)
   {
   case 0:
      wcout << L"Employee with id " << id << L" has salary " 
            << receive(find_id_result);
      break;
   case 1:
      wcout << L"Employee with salary " << salary << L" has id " 
            << receive(find_salary_result);
      break;
   case 2:
      wcout << L"No employee has id " << id << L" or salary " << salary;
      break;
   default:
      __assume(0);
   }
   wcout << L'.' << endl;

   // Cancel any active tasks and wait for the task group to finish.
   tasks.cancel();
   tasks.wait();
}

int wmain()
{
   // Create an array of employees and assign each one a 
   // random id and salary.

   array<employee, 10000> employees;

   mt19937 gen(15);
   const float base_salary = 25000.0f;
   for (int i = 0; i < employees.size(); ++i)
   {
      employees[i].id = gen()%100000;

      float bonus = static_cast<float>(gen()%5000);
      employees[i].salary = base_salary + bonus;
   }

   // Search for several id and salary values.

   find_employee(employees, 14758, 30210.00);
   find_employee(employees, 340, 29150.00);
   find_employee(employees, 61935, 29255.90);
   find_employee(employees, 899, 31223.00);
}

この例を実行すると、次の出力が生成されます。

Employee with id 14758 has salary 27780.00.
Employee with salary 29150.00 has id 84345.
Employee with id 61935 has salary 29905.00.
No employee has id 899 or salary 31223.00.

この例は、Concurrency::make_choice ヘルパー関数を使用して choice オブジェクトを作成し、Concurrency::make_join ヘルパー関数を使用して join オブジェクトを作成します。

コードのコンパイル

プログラム例をコピーし、Visual Studio プロジェクトに貼り付けるか、find-employee.cpp という名前のファイルに貼り付け、Visual Studio 2010 のコマンド プロンプト ウィンドウで次のコマンドを実行します。

cl.exe /EHsc find-employee.cpp

参照

参照

choice クラス

join クラス

概念

非同期エージェント ライブラリ

非同期メッセージ ブロック

メッセージ パッシング関数