共用方式為


如何:在已完成的工作之中選取

此範例說明如何使用 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(begin(employees), end(employees), 
         [&](const employee& e) { return e.id == id; });
      if (result != end(employees))
      {
         // 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(begin(employees), end(employees), 
         [&](const employee& e) { return e.salary == salary; });
      if (result != end(employees))
      {
         // 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);
}

這個範例產生下列輸出。

  

此範例會使用 concurrency::make_choice Helper 函式來建立 choice 物件,並使用 concurrency::make_join Helper 函數來建立 join 物件。

編譯程式碼

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

cl.exe /EHsc find-employee.cpp

請參閱

參考

choice 類別

join 類別

概念

非同步代理程式程式庫

非同步訊息區

訊息傳遞函式