Comment : effectuer une sélection parmi les tâches terminées
Cet exemple montre comment utiliser les classes concurrency::choice et concurrency::join pour sélectionner la première tâche afin de terminer un algorithme de recherche.
Exemple
L'exemple suivant effectue deux algorithmes de recherche en parallèle et sélectionne le premier algorithme à terminer. Cet exemple définit le type employee, qui contient un identificateur numérique et un salaire pour un employé. La fonction find_employee recherche le premier employé qui a l'identificateur fourni ou le salaire fourni. La fonction find_employee gère également le cas où aucun employé n'a l'identificateur ou salaire fourni. La fonction wmain crée un tableau d'objets employee et recherche plusieurs valeurs de salaire et d'identificateur.
L'exemple utilise un objet choice pour effectuer une sélection parmi les cas suivants :
Il existe un employé qui a l'identificateur fourni.
Il existe un employé qui a le salaire fourni.
Il n'existe aucun employé qui a l'identificateur ou le salaire fourni.
Pour les deux premiers cas, l'exemple utilise un objet concurrency::single_assignment pour stocker l'identificateur et un autre objet single_assignment pour stocker le salaire. L'exemple utilise un objet join pour le troisième cas. L'objet join est composé de deux objets single_assignment supplémentaires, un pour le cas où il n'existe aucun employé avec l'identificateur fourni et un pour le cas où il n'existe aucun employé avec le salaire fourni. L'objet join envoie un message lorsque chacun de ses membres reçoit un message. Dans cet exemple, l'objet join envoie un message lorsqu'il n'existe aucun employé avec l'identificateur ou le salaire fourni.
L'exemple utilise un objet concurrency::structured_task_group pour exécuter les deux algorithmes de recherche en parallèle. Chaque tâche de recherche écrit dans l'un des objets single_assignment pour indiquer si l'employé donné existe. L'exemple utilise la fonction concurrency::receive pour obtenir l'index de la première mémoire tampon qui contient un message et un bloc switch pour imprimer le résultat.
// 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, ¬_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);
}
Cet exemple génère la sortie suivante.
Cet exemple utilise la fonction d'assistance concurrency::make_choice pour créer des objets choice et la fonction d'assistance concurrency::make_join pour créer des objets join.
Compilation du code
Copiez l'exemple de code et collez-le dans un projet Visual Studio , ou collez-le dans un fichier nommé find-employee.cpp puis exécutez la commande suivante dans une fenêtre d'invite de commandes Visual Studio.
cl.exe /EHsc find-employee.cpp