Como selecionar tarefas concluídas

Este exemplo mostra como usar as classes concurrency::choice e concurrency::join para selecionar a primeira tarefa e concluir um algoritmo de pesquisa.

Exemplo

O exemplo a seguir executa dois algoritmos de pesquisa em paralelo e seleciona o primeiro algoritmo a ser concluído. Este exemplo define o tipo employee, que contém um identificador numérico e um salário para um funcionário. A função find_employee localiza o primeiro funcionário que tem o identificador fornecido ou o salário fornecido. A função find_employee também lida do caso em que nenhum funcionário tem o identificador ou salário fornecido. A função wmain cria uma matriz de objetos employee e pesquisa diversos identificadores e valores salariais.

O exemplo usa um objeto choice para selecionar entre os seguintes casos:

  1. Há um funcionário que tem o identificador fornecido.

  2. Há um funcionário que tem o salário fornecido.

  3. Não há funcionários que tenham o identificador ou o salário fornecido.

Para os dois primeiros casos, o exemplo usa um objeto concurrency::single_assignment para armazenar o identificador e outro objeto single_assignment para armazenar o salário. O exemplo usa um objeto join para o terceiro caso. O objeto join é composto por dois objetos single_assignment adicionais, um para o caso em que não há funcionários que tenham o identificador fornecido e outro para o caso em que não há funcionários que tenham o salário fornecido. O objeto join envia uma mensagem quando cada um dos membros recebe uma mensagem. Neste exemplo, o objeto join envia uma mensagem quando não há funcionários que tenham o identificador ou o salário fornecido.

O exemplo usa um objeto concurrency::structured_task_group para executar os dois algoritmos de pesquisa em paralelo. Cada tarefa de pesquisa grava em um dos objetos single_assignment para indicar se o funcionário fornecido existe. O exemplo usa a função concurrency::receive para obter o índice do primeiro buffer que contém uma mensagem e um bloco switch para imprimir o 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 exemplo gerencia a seguinte saída.

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.

Este exemplo usa a função auxiliar concurrency::make_choice para criar objetos choice e a função auxiliar concurrency::make_join para criar objetos join.

Compilando o código

Copie o código de exemplo e cole-o em um projeto do Visual Studio, ou cole-o em um arquivo chamado find-employee.cpp e execute o comando a seguir em uma janela do Prompt de comando do Visual Studio.

cl.exe /EHsc find-employee.cpp

Confira também

Biblioteca de agentes assíncronos
Blocos de mensagens assíncronos
Funções de transmissão de mensagem
Classe choice
Classe join