Практическое руководство. Использование фильтра блока сообщений
В этом документе показано, как использовать функцию фильтрации, чтобы позволить асинхронному блоку сообщений принимать или отклонять сообщения в зависимости от их полезной нагрузки.
При создании объекта блокировать сообщения, такие как concurrency::unbounded_buffer, concurrency::call, или concurrency::transformer, можно указать функцию фильтра , определяет ли блок сообщений принимает или отклоняет сообщение.Функция фильтрации позволяет блоку сообщений получать только определенные значения.
Функции фильтрации важны, так как они позволяют соединять блоки сообщений в сети потока данных.В сети потока данных блоки сообщений управляют потоком данных, обрабатывая только сообщения, удовлетворяющие определенным критериям.Это отличается от модели потока управления, где поток данных контролируется с помощью структур управления, например условных операторов, циклов и так далее.
В этом документе содержится основной пример использования фильтра сообщений.Дополнительные примеры использования фильтров сообщений и модели потока данных для соединения блоков сообщений см. в разделах Пошаговое руководство. Создание агента потоков данных и Пошаговое руководство. Создание сети обработки изображений.
Пример
Рассмотрим следующую функцию, count_primes, показывающую основное использование блока сообщений, не фильтрующего входящие сообщения.Блок сообщений добавляет простые числа к объекту std::vector.Функция count_primes отправляет несколько чисел блоку сообщений, принимает выходные значения от блока сообщений и выводит простые числа на консоль.
// 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;
}
}
Объект transformer обрабатывает все входные значения; при этом требуются только простые числа.Можно было написать приложение так, чтобы отправитель сообщений отправлял только простые числа, но требования получателя сообщений не всегда известны.
Следующая функция, count_primes_filter, выполняет ту же задачу, что и функция count_primes.При этом объект transformer в этой версии использует функцию фильтрации, чтобы принимать только простые числа.Функция, выполняющая действие, принимает только простые числа; поэтому ей не нужно вызывать функцию is_prime.
Так как объект transformer принимает только простые числа, объект transformer может сам содержать простые числа.Иными словами, объект transformer в этом примере не должен добавлять простые числа к объекту 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;
}
}
После этого объект transformer обрабатывает только простые числа.В предыдущем примере объект transformer обрабатывает все сообщения.Поэтому в нем количества получаемых и отправляемых сообщений должны совпадать.В этом примере результат concurrency::send функции, чтобы определить, сколько сообщений для получения от transformer объект.Функция send возвращает значение true, если буфер сообщений принимает значение, и значение false, если буфер сообщений отклоняет сообщение.Поэтому количество простых чисел совпадает с количеством сообщений, принятых буфером сообщений.
Ниже приведен полный пример кода.Пример вызывает и функцию count_primes, и функцию count_primes_filter.
// 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
*/
}
В этом примере получается следующий результат:
Without filtering:
The following numbers are prime:
9973
9349
9241
8893
1297
7127
8647
3229
With filtering:
The following numbers are prime:
9973
9349
9241
8893
1297
7127
8647
3229
Компиляция кода
Скопируйте код и вставьте его в проект Visual Studio или вставьте его в файл с именем блоков filter.cpp и запустите следующую команду в окне командной строки Visual Studio.
cl.exe /EHsc primes-filter.cpp
Отказоустойчивость
Функция фильтрации может быть лямбда-функцией, указателем функции или объектом функции.Любая функция фильтрации принимает одну из следующих форм.
bool (_Type)
bool (_Type const &)
Чтобы исключить лишнее копирование данных, при работе с составным типом, передаваемым по значению, следует использовать вторую форму.
См. также
Задачи
Пошаговое руководство. Создание агента потоков данных
Пошаговое руководство. Создание сети обработки изображений