如何:在已完成的任务之间选择

本示例演示如何使用 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 类

概念

异步代理库

异步消息块

消息传递函数