Partager via


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_primesqui 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_filtereffectue 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