共用方式為


HOW TO:在已完成的工作之中選取

此範例說明如何使用 Concurrency::choiceConcurrency::join 類別,選取第一項要完成搜尋演算法的工作。

範例

下列範例會以平行方式執行兩個搜尋演算法,並選取第一個要完成的演算法。 此範例會定義 employee 類型;此類型包含某員工的數值識別碼和薪資。 find_employee 函式會尋找第一個具有所提供之識別碼或薪資的員工。 find_employee 函式也會在沒有任何員工具有提供的識別碼或薪資時,處理此一情況。 wmain 函式會建立 employee 物件的陣列,並搜尋數個識別碼和薪資值。

此範例會使用 choice 物件來選取下列情況:

  1. 有員工具有提供的識別碼。

  2. 有員工具有提供的薪資。

  3. 沒有任何員工具有提供的識別碼或薪資。

在前兩種的情況中,此範例會使用 Concurrency::single_assignment 物件保存識別碼,並使用另一個 single_assignment 物件保存薪資。 對於第三種情況,此範例會使用 join 物件。 join 物件由其他兩個 single_assignment 物件所組成,一個適用於沒有任何員工具有提供的識別碼時,另一個則適用於沒有任何員工具有提供的新資時。 join 物件會在其每個成員皆收到訊息時傳送訊息。 在此範例中,join 物件會在沒有任何員工具有提供的識別碼或薪資時傳送訊息。

此範例會使用 Concurrency::structured_task_group 物件,以平行方式執行這兩個搜尋演算法。 每項搜尋工作分別會寫入到其中一個 single_assignment 物件,以指出指定的員工是否存在。 此範例會使用 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 Helper 函式來建立 choice 物件,並使用 Concurrency::make_join Helper 函數來建立 join 物件。

編譯程式碼

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

cl.exe /EHsc find-employee.cpp

請參閱

參考

choice 類別

join 類別

概念

非同步代理程式程式庫

非同步訊息區

訊息傳遞函式