共用方式為


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

這個範例產生下列輸出。

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 專案中,或將它貼在檔名為尋找 employee.cpp ,然後執行下列命令,Visual Studio 的命令提示字元] 視窗中。

cl.exe /EHsc find-employee.cpp

請參閱

參考

choice 類別

join 類別

概念

非同步代理程式程式庫

非同步訊息區

訊息傳遞函式