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_primes
któ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_filter
wykonuje 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