Compartir vía


Cómo: Seleccionar tareas completadas

En este ejemplo se muestra cómo usar las clases concurrency::choice y concurrency::join para seleccionar la primera tarea y completar un algoritmo de búsqueda.

Ejemplo

En el ejemplo siguiente se ejecutan dos algoritmos de búsqueda en paralelo y se selecciona el primer algoritmo para que se complete. En este ejemplo se define el tipo employee, que almacena un identificador numérico y un sueldo para un empleado. La función find_employee encuentra al primer empleado que tiene el identificador o el sueldo especificados. La función find_employee también controla el caso en el que ningún empleado tiene el identificador o el sueldo especificados. La función wmain crea una matriz de objetos employee y busca varios valores del identificador y del sueldo.

En el ejemplo se usa un objeto choice para realizar la selección entre los siguientes casos:

  1. Existe un empleado que tiene el identificador especificado.

  2. Existe un empleado que tiene el sueldo especificado.

  3. No existe ningún empleado con el identificador o el sueldo especificados.

En el ejemplo, en los dos primeros casos se usa un objeto concurrency::single_assignment para almacenar el identificador y otro objeto single_assignment para almacenar el salario. En el ejemplo se usa un objeto join para el tercer caso. El objeto join se compone de dos objetos single_assignment adicionales, uno para el caso en el que no existe ningún empleado con el identificador especificado y otro para el caso en el que no existe ningún empleado con el sueldo especificado. El objeto join envía un mensaje cuando cada uno de sus miembros recibe un mensaje. En este ejemplo, el objeto join envía un mensaje cuando no existe ningún empleado con el identificador o el sueldo especificados.

En el ejemplo se usa un objeto concurrency::structured_task_group para ejecutar ambos algoritmos de búsqueda en paralelo. Cada tarea de búsqueda escribe en uno de los objetos single_assignment para indicar si existe el empleado especificado. En el ejemplo se usa la función concurrency::receive para obtener el índice del primer búfer que contiene un mensaje y un bloque switch para imprimir el resultado.

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

Este ejemplo produce el siguiente resultado:

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.

En este ejemplo se usa la función del asistente concurrency::make_choice para crear objetos de choice y la función del asistente concurrency::make_join para crear objetos join.

Compilar el código

Copie el código de ejemplo y péguelo en un proyecto de Visual Studio o en un archivo denominado find-employee.cpp y, después, ejecute el siguiente comando en una ventana del símbolo del sistema de Visual Studio.

cl.exe /EHsc find-employee.cpp

Consulte también

Biblioteca de agentes asincrónicos
Bloques de mensajes asincrónicos
Funciones que pasan mensajes
choice (clase)
join (clase)