Comment : utiliser un filtre de bloc de message
Ce document montre comment utiliser une fonction de filtre pour permettre à un bloc de message asynchrone d’accepter ou de rejeter un message en fonction de la charge utile de ce message.
Lorsque vous créez un objet de bloc de messages tel qu’une concurrence ::unbounded_buffer, une concurrence ::call ou une concurrence ::transformer, vous pouvez fournir une fonction de filtre qui détermine si le bloc de messages accepte ou rejette un message. Une fonction de filtre est un moyen utile de garantir qu’un bloc de messages ne reçoit que certaines valeurs.
Les fonctions de filtre sont importantes, car elles vous permettent de connecter des blocs de messages pour former des réseaux de flux de données. Dans un réseau de flux de données, les messages bloquent le flux de données en traitant uniquement les messages qui répondent à des critères spécifiques. Comparez-le au modèle de flux de contrôle, où le flux de données est réglementé à l’aide de structures de contrôle telles que des instructions conditionnelles, des boucles, etc.
Ce document fournit un exemple de base de l’utilisation d’un filtre de message. Pour obtenir des exemples supplémentaires qui utilisent des filtres de messages et le modèle de flux de données pour connecter des blocs de messages, consultez Procédure pas à pas : Création d’un agent de flux de données et procédure pas à pas : création d’un réseau de traitement d’images.
Exemple : fonction count_primes
Considérez la fonction suivante, count_primes
qui illustre l’utilisation de base d’un bloc de messages qui ne filtre pas les messages entrants. Le bloc de messages ajoute des nombres premiers à un objet std ::vector . La count_primes
fonction envoie plusieurs nombres au bloc de message, reçoit les valeurs de sortie du bloc de messages et imprime ces nombres qui sont premiers dans la console.
// Illustrates usage of a message buffer that does not use filtering.
void count_primes(unsigned long random_seed)
{
// Holds prime numbers.
vector<unsigned long> primes;
// Adds numbers that are prime to the vector object.
transformer<unsigned long, unsigned long> t([&primes](unsigned long n) -> unsigned long
{
if (is_prime(n))
{
primes.push_back(n);
}
return n;
});
// Send random values to the message buffer.
mt19937 generator(random_seed);
for (int i = 0; i < 20; ++i)
{
send(t, static_cast<unsigned long>(generator()%10000));
}
// Receive from the message buffer the same number of times
// to ensure that the message buffer has processed each message.
for (int i = 0; i < 20; ++i)
{
receive(t);
}
// Print the prime numbers to the console.
wcout << L"The following numbers are prime: " << endl;
for(unsigned long prime : primes)
{
wcout << prime << endl;
}
}
L’objet transformer
traite toutes les valeurs d’entrée ; toutefois, il ne nécessite que les valeurs qui sont primaires. Bien que l’application puisse être écrite afin que l’expéditeur du message envoie uniquement des nombres premiers, les exigences du récepteur de messages ne peuvent pas toujours être connues.
Exemple : fonction count_primes_filter
La fonction suivante, , count_primes_filter
effectue la même tâche que la count_primes
fonction. Toutefois, l’objet transformer
de cette version utilise une fonction de filtre pour accepter uniquement les valeurs qui sont principales. La fonction qui effectue l’action reçoit uniquement les nombres premiers ; par conséquent, il n’est pas obligé d’appeler la is_prime
fonction.
Étant donné que l’objet transformer
reçoit uniquement des nombres premiers, l’objet transformer
lui-même peut contenir les nombres premiers. En d’autres termes, l’objet transformer
de cet exemple n’est pas nécessaire pour ajouter les nombres premiers à l’objet vector
.
// Illustrates usage of a message buffer that uses filtering.
void count_primes_filter(unsigned long random_seed)
{
// Accepts numbers that are prime.
transformer<unsigned long, unsigned long> t([](unsigned long n) -> unsigned long
{
// The filter function guarantees that the input value is prime.
// Return the input value.
return n;
},
nullptr,
[](unsigned long n) -> bool
{
// Filter only values that are prime.
return is_prime(n);
});
// Send random values to the message buffer.
mt19937 generator(random_seed);
size_t prime_count = 0;
for (int i = 0; i < 20; ++i)
{
if (send(t, static_cast<unsigned long>(generator()%10000)))
{
++prime_count;
}
}
// Print the prime numbers to the console.
wcout << L"The following numbers are prime: " << endl;
while (prime_count-- > 0)
{
wcout << receive(t) << endl;
}
}
L’objet transformer
traite désormais uniquement les valeurs qui sont principales. Dans l’exemple précédent, transformer
l’objet traite tous les messages. Par conséquent, l’exemple précédent doit recevoir le même nombre de messages qu’il envoie. Cet exemple utilise le résultat de la fonction concurrency ::send pour déterminer le nombre de messages à recevoir de l’objet transformer
. La send
fonction retourne true
lorsque la mémoire tampon du message accepte le message et false
lorsque la mémoire tampon du message rejette le message. Par conséquent, le nombre de fois où la mémoire tampon du message accepte le message correspond au nombre de nombres premiers.
Exemple : exemple de code de filtre de bloc de messages terminé
L'exemple de code suivant illustre l'exemple complet. L’exemple appelle à la fois la count_primes
fonction et la count_primes_filter
fonction.
// primes-filter.cpp
// compile with: /EHsc
#include <agents.h>
#include <algorithm>
#include <iostream>
#include <random>
using namespace concurrency;
using namespace std;
// Determines whether the input value is prime.
bool is_prime(unsigned long n)
{
if (n < 2)
return false;
for (unsigned long i = 2; i < n; ++i)
{
if ((n % i) == 0)
return false;
}
return true;
}
// Illustrates usage of a message buffer that does not use filtering.
void count_primes(unsigned long random_seed)
{
// Holds prime numbers.
vector<unsigned long> primes;
// Adds numbers that are prime to the vector object.
transformer<unsigned long, unsigned long> t([&primes](unsigned long n) -> unsigned long
{
if (is_prime(n))
{
primes.push_back(n);
}
return n;
});
// Send random values to the message buffer.
mt19937 generator(random_seed);
for (int i = 0; i < 20; ++i)
{
send(t, static_cast<unsigned long>(generator()%10000));
}
// Receive from the message buffer the same number of times
// to ensure that the message buffer has processed each message.
for (int i = 0; i < 20; ++i)
{
receive(t);
}
// Print the prime numbers to the console.
wcout << L"The following numbers are prime: " << endl;
for(unsigned long prime : primes)
{
wcout << prime << endl;
}
}
// Illustrates usage of a message buffer that uses filtering.
void count_primes_filter(unsigned long random_seed)
{
// Accepts numbers that are prime.
transformer<unsigned long, unsigned long> t([](unsigned long n) -> unsigned long
{
// The filter function guarantees that the input value is prime.
// Return the input value.
return n;
},
nullptr,
[](unsigned long n) -> bool
{
// Filter only values that are prime.
return is_prime(n);
});
// Send random values to the message buffer.
mt19937 generator(random_seed);
size_t prime_count = 0;
for (int i = 0; i < 20; ++i)
{
if (send(t, static_cast<unsigned long>(generator()%10000)))
{
++prime_count;
}
}
// Print the prime numbers to the console.
wcout << L"The following numbers are prime: " << endl;
while (prime_count-- > 0)
{
wcout << receive(t) << endl;
}
}
int wmain()
{
const unsigned long random_seed = 99714;
wcout << L"Without filtering:" << endl;
count_primes(random_seed);
wcout << L"With filtering:" << endl;
count_primes_filter(random_seed);
/* Output:
9973
9349
9241
8893
1297
7127
8647
3229
With filtering:
The following numbers are prime:
9973
9349
9241
8893
1297
7127
8647
3229
*/
}
Compilation du code
Copiez l’exemple de code et collez-le dans un projet Visual Studio, ou collez-le dans un fichier nommé primes-filter.cpp
, puis exécutez la commande suivante dans une fenêtre d’invite de commandes Visual Studio.
cl.exe /EHsc primes-filter.cpp
Programmation fiable
Une fonction de filtre peut être une fonction lambda, un pointeur de fonction ou un objet de fonction. Chaque fonction de filtre prend l’une des formes suivantes :
bool (T)
bool (T const &)
Pour éliminer la copie inutile de données, utilisez le deuxième formulaire lorsque vous avez un type d’agrégation transmis par valeur.
Voir aussi
Bibliothèque d’agents asynchrones
Procédure pas à pas : création des agents de flux de données
Procédure pas à pas : création d’un réseau de traitement d’image
transformer, classe