Dela via


Anvisningar: Använd ett filter för meddelandeblockering

Det här dokumentet visar hur du använder en filterfunktion för att aktivera ett asynkront meddelandeblock för att acceptera eller avvisa ett meddelande på grundval av nyttolasten för det meddelandet.

När du skapar ett meddelandeblocksobjekt, till exempel en samtidighet::unbounded_buffer, en samtidighet::anrop eller en samtidighet::transformer, kan du ange en filterfunktion som avgör om meddelandeblocket accepterar eller avvisar ett meddelande. En filterfunktion är ett användbart sätt att garantera att ett meddelandeblock endast tar emot vissa värden.

Filterfunktioner är viktiga eftersom de gör att du kan ansluta meddelandeblock för att bilda dataflödesnätverk. I ett dataflödesnätverk styr meddelandeblock dataflödet genom att endast bearbeta de meddelanden som uppfyller specifika kriterier. Jämför detta med kontrollflödesmodellen, där dataflödet regleras med hjälp av kontrollstrukturer som villkorssatser, loopar och så vidare.

Det här dokumentet innehåller ett grundläggande exempel på hur du använder ett meddelandefilter. Ytterligare exempel som använder meddelandefilter och dataflödesmodellen för att ansluta meddelandeblock finns i Genomgång: Skapa en dataflödesagent och genomgång: Skapa ett Image-Processing nätverk.

Exempel: funktionen count_primes

Tänk på följande funktion, count_primes, som illustrerar den grundläggande användningen av ett meddelandeblock som inte filtrerar inkommande meddelanden. Meddelandeblocket lägger till primtal i ett std::vector-objekt . Funktionen count_primes skickar flera tal till meddelandeblocket, tar emot utdatavärdena från meddelandeblocket och skriver ut de tal som är primära i konsolen.

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

Objektet transformer bearbetar alla indatavärden, men det kräver bara de värden som är primära. Även om programmet kan skrivas så att meddelandesändaren endast skickar primtal, kan kraven för meddelandemottagaren inte alltid vara kända.

Exempel: funktionen count_primes_filter

Följande funktion, count_primes_filter, utför samma uppgift som count_primes funktionen. Objektet i den transformer här versionen använder dock en filterfunktion för att endast acceptera de värden som är primära. Funktionen som utför åtgärden tar bara emot primtal. Därför behöver den inte anropa is_prime funktionen.

Eftersom objektet transformer endast tar emot primtal transformer kan själva objektet innehålla de primära talen. Med andra ord krävs inte objektet transformer i det här exemplet för att lägga till primtalen i vector objektet.

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

Objektet transformer bearbetar nu endast de värden som är primära. I föregående exempel transformer bearbetar objektet alla meddelanden. Därför måste det föregående exemplet ta emot samma antal meddelanden som det skickar. I det här exemplet används resultatet av funktionen concurrency::send för att avgöra hur många meddelanden som transformer ska ta emot från objektet. Funktionen send returnerar true när meddelandebufferten accepterar meddelandet och false när meddelandebufferten avvisar meddelandet. Därför matchar antalet gånger som meddelandebufferten accepterar meddelandet antalet primtal.

Exempel: Kodexempel för meddelandeblockering har slutförts

Följande kod visar det fullständiga exemplet. Exemplet anropar både count_primes funktionen och count_primes_filter funktionen.

// 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
    */
}

Kompilera koden

Kopiera exempelkoden och klistra in den i ett Visual Studio-projekt, eller klistra in den i en fil med namnet primes-filter.cpp och kör sedan följande kommando i ett Visual Studio-kommandotolkfönster.

cl.exe /EHsc primes-filter.cpp

Robust Programmering

En filterfunktion kan vara en lambda-funktion, en funktionspekare eller ett funktionsobjekt. Varje filterfunktion har något av följande formulär:

bool (T)
bool (T const &)

Om du vill eliminera onödig kopiering av data använder du det andra formuläret när du har en aggregeringstyp som överförs med värde.

Se även

Asynkront agentbibliotek
Genomgång: Skapa en dataflödesagent
Genomgång: Skapa ett Image-Processing nätverk
transformeringsklass