Como usar um filtro de bloco de mensagens
Este documento demonstra como usar uma função de filtro para habilitar um bloco de mensagens assíncrona para aceitar ou rejeitar uma mensagem com base na carga dessa mensagem.
Quando você cria um objeto do bloco de mensagem como concurrency::unbounded_buffer, concurrency::call, ou concurrency::transformer, você pode fornecer uma função de filtro que determina se o pacote de mensagem aceita ou descarta uma mensagem. Uma função de filtro é uma maneira útil para garantir que um bloco de mensagem recebe apenas determinados valores.
As funções de filtro é importante porque permitem a conexão blocos de mensagem para formar redes de fluxo de dados. Em uma rede de fluxo de dados, os blocos de mensagem controlam o fluxo de dados processando somente as mensagens que atendem a critérios específicos. Compare isso ao modelo de fluxo de controle, onde o fluxo de dados é regulado usando estruturas de controle como instruções condicionais, loop, e assim por diante.
Este documento fornece um exemplo básico sobre como usar um filtro de mensagem. Para obter exemplos adicionais que usam filtros da mensagem e o modelo de fluxo de dados para se conectar blocos de mensagem, consulte Instruções passo a passo: criando um agente de fluxo de dados e Instruções passo a passo: criando uma rede de processamento de imagem.
Exemplo
Considere a seguinte função, count_primes, que ilustra o uso básico de um bloco de mensagem que não filtra as mensagens de entrada. O bloco de mensagem acrescenta números principais para um objeto de std::vector . A função de count_primes envia vários números para o bloco da mensagem, recebe os valores de saída do bloco de mensagem, e imprimir os números que são principais no 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;
}
}
O objeto de transformer processa todos os valores de entrada; porém, isso requer apenas os valores que principais. Embora o aplicativo poderia ser escrito de modo que o remetente da mensagem envie apenas números à esquerda, os requisitos do destinatário da mensagem não podem sempre ser conhecidos.
A seguinte função, count_primes_filter, executa a mesma tarefa que a função de count_primes . No entanto, o objeto de transformer nesta versão usa uma função de filtro para aceitar apenas os valores que principais. A função que executa a ação recebe apenas números principais; consequentemente, não precisa chamar a função de is_prime .
Como o objeto de transformer recebe apenas números à esquerda, o próprio objeto de transformer pode manter os números à esquerda. Ou seja o objeto de transformer neste exemplo não é necessário adicionar os números principais ao objeto de 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;
}
}
O objeto de transformer processar agora apenas os valores que principais. No exemplo anterior, o objeto de transformer processa todas as mensagens. Em virtude disso, o exemplo anterior deve receber o mesmo número de mensagens que o envia. Este exemplo usa o resultado da função de concurrency::send para determinar quantas mensagens a serem recebidos de transformer objeto. A função de send retorna true quando o buffer de mensagem aceita a mensagem e false quando o buffer de mensagem descartará a mensagem. Consequentemente, o número de vezes que o buffer de mensagem aceita a mensagem corresponde a contagem de números à esquerda.
O código a seguir mostra o exemplo completo. O exemplo chama a função de count_primes e a função de 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
*/
}
Compilando o código
Copie o código de exemplo e cole-o em um projeto do Visual Studio, ou cole-o em um arquivo chamado primes-filter.cpp e execute o comando a seguir em uma janela de prompt de comando do Visual Studio.
cl.exe /EHsc primes-filter.cpp
Programação robusta
Uma função de filtro pode ser uma função de lambda, um ponteiro de função, ou um objeto da função. Cada função de filtro usa uma das seguintes formas:
Para eliminar a cópia desnecessária de dados, use o segundo formulário quando você tem um tipo de agregação que seja passado pelo valor.
Consulte também
Tarefas
Instruções passo a passo: criando um agente de fluxo de dados
Instruções passo a passo: criando uma rede de processamento de imagem