Udostępnij za pośrednictwem


Porady: korzystanie z filtra bloku komunikatów

W tym dokumencie pokazano, jak za pomocą funkcji filtru włączyć asynchroniczny blok komunikatów do akceptowania lub odrzucania komunikatu na podstawie ładunku tego komunikatu.

Podczas tworzenia obiektu bloku komunikatów, takiego jak współbieżność::unbounded_buffer, współbieżność::call lub współbieżność::transformer, można podać funkcję filtru, która określa, czy blok komunikatów akceptuje lub odrzuca komunikat. Funkcja filtru to przydatny sposób zagwarantowania, że blok komunikatów odbiera tylko określone wartości.

Funkcje filtrowania są ważne, ponieważ umożliwiają łączenie bloków komunikatów z sieciami przepływu danych. W sieci przepływu danych bloki komunikatów kontrolują przepływ danych, przetwarzając tylko te komunikaty spełniające określone kryteria. Porównaj to z modelem przepływu sterowania, w którym przepływ danych jest regulowany przy użyciu struktur sterujących, takich jak instrukcje warunkowe, pętle itd.

Ten dokument zawiera podstawowy przykład używania filtru komunikatów. Aby uzyskać dodatkowe przykłady, które używają filtrów komunikatów i modelu przepływu danych do łączenia bloków komunikatów, zobacz Przewodnik: Tworzenie agenta przepływu danych i Przewodnik: tworzenie sieci przetwarzania obrazów.

Przykład: funkcja count_primes

Rozważmy następującą funkcję , count_primesktóra ilustruje podstawowe użycie bloku komunikatów, który nie filtruje komunikatów przychodzących. Blok komunikatów dołącza liczby prime do obiektu std::vector . Funkcja count_primes wysyła kilka liczb do bloku komunikatów, odbiera wartości wyjściowe z bloku komunikatów i drukuje te numery, które są prime do konsoli.

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

Obiekt transformer przetwarza wszystkie wartości wejściowe, jednak wymaga tylko tych wartości, które są prime. Chociaż aplikacja może być napisana tak, aby nadawca wiadomości wysyłał tylko liczby pierwsze, wymagania odbiorcy komunikatów nie zawsze mogą być znane.

Przykład: funkcja count_primes_filter

Następująca funkcja , count_primes_filterwykonuje to samo zadanie co count_primes funkcja. transformer Jednak obiekt w tej wersji używa funkcji filtru do akceptowania tylko tych wartości, które są prime. Funkcja wykonująca akcję otrzymuje tylko liczby pierwsze; w związku z tym nie musi wywoływać is_prime funkcji.

transformer Ponieważ obiekt otrzymuje tylko liczby pierwsze, transformer sam obiekt może przechowywać liczby pierwsze. Innymi słowy, transformer obiekt w tym przykładzie nie jest wymagany do dodania liczb pierwszych do vector obiektu.

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

Obiekt transformer przetwarza teraz tylko te wartości, które są prime. W poprzednim przykładzie transformer obiekt przetwarza wszystkie komunikaty. W związku z tym w poprzednim przykładzie musi zostać odebrana ta sama liczba wysyłanych komunikatów. W tym przykładzie użyto wyniku funkcji concurrency::send , aby określić liczbę komunikatów odbieranych z transformer obiektu. Funkcja send jest zwracana true , gdy bufor komunikatu akceptuje komunikat, a false bufor komunikatu odrzuca komunikat. W związku z tym liczba akceptowanych przez bufor komunikatów odpowiada liczbie liczb pierwszych.

Przykład: gotowy kod filtru bloku komunikatów

Poniższy kod przedstawia kompletny przykład. W przykładzie wywoływana jest count_primes zarówno funkcja, jak count_primes_filter i funkcja.

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

Kompilowanie kodu

Skopiuj przykładowy kod i wklej go w projekcie programu Visual Studio lub wklej go w pliku o nazwie primes-filter.cpp , a następnie uruchom następujące polecenie w oknie wiersza polecenia programu Visual Studio.

cl.exe /EHsc primes-filter.cpp

Niezawodne programowanie

Funkcja filtru może być funkcją lambda, wskaźnikiem funkcji lub obiektem funkcji. Każda funkcja filter przyjmuje jedną z następujących form:

bool (T)
bool (T const &)

Aby wyeliminować niepotrzebne kopiowanie danych, użyj drugiego formularza, gdy masz typ agregacji przesyłany przez wartość.

Zobacz też

Biblioteki agentów asynchronicznych
Przewodnik: tworzenie agenta przepływu danych
Przewodnik: tworzenie sieci przetwarzania obrazów
transformer, klasa