Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Este documento demonstra como usar uma função de filtro para permitir que um bloco de mensagem assíncrona aceite ou rejeite uma mensagem com base na carga dessa mensagem.
Quando você cria um objeto de bloco de mensagem, como uma simultaneidade::unbounded_buffer, uma simultaneidade::call ou uma simultaneidade::transformer, você pode fornecer uma função de filtro que determina se o bloco de mensagem aceita ou rejeita uma mensagem. Uma função de filtro é uma maneira útil de garantir que um bloco de mensagens receba apenas determinados valores.
As funções de filtro são importantes porque permitem conectar blocos de mensagens para formar redes de fluxo de dados. Em uma rede de fluxo de dados, os blocos de mensagens controlam o fluxo de dados processando apenas as mensagens que atendem a critérios específicos. Compare isso com o modelo de fluxo de controle, onde o fluxo de dados é regulado usando estruturas de controle, como instruções condicionais, loops e assim por diante.
Este documento fornece um exemplo básico de como usar um filtro de mensagens. Para obter exemplos adicionais que usam filtros de mensagens e o modelo de fluxo de dados para conectar blocos de mensagens, consulte Passo a passo: Criando um agente de fluxo de dados e Passo a passo: Criando uma rede Image-Processing.
Exemplo: função count_primes
Considere a seguinte função, count_primes, que ilustra o uso básico de um bloco de mensagens que não filtra as mensagens recebidas. O bloco de mensagem acrescenta números primos a um objeto std::vetor . A count_primes função envia vários números para o bloco de mensagens, recebe os valores de saída do bloco de mensagens e imprime os números primos para o 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 transformer objeto processa todos os valores de entrada, no entanto, requer apenas os valores primos. Embora o aplicativo possa ser escrito de modo que o remetente da mensagem envie apenas números primos, os requisitos do recetor da mensagem nem sempre podem ser conhecidos.
Exemplo: função count_primes_filter
A seguinte função, count_primes_filter, executa a mesma tarefa que a count_primes função. No entanto, o transformer objeto nesta versão usa uma função de filtro para aceitar apenas os valores que são primos. A função que executa a ação recebe apenas números primos; portanto, ele não precisa chamar a is_prime função.
Como o transformer objeto recebe apenas números primos, o transformer próprio objeto pode conter os números primos. Em outras palavras, o transformer objeto neste exemplo não é necessário para adicionar os números primos ao vector objeto.
// 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 transformer objeto agora processa apenas os valores primos. No exemplo anterior, transformer o objeto processa todas as mensagens. Portanto, o exemplo anterior deve receber o mesmo número de mensagens que envia. Este exemplo usa o resultado da função concurrency::send para determinar quantas mensagens receber do transformer objeto. A send função retorna true quando o buffer de mensagens aceita a mensagem e false quando o buffer de mensagens rejeita a mensagem. Portanto, o número de vezes que o buffer de mensagens aceita a mensagem corresponde à contagem de números primos.
Exemplo: Exemplo de código de filtro de bloco de mensagem concluído
O código a seguir mostra o exemplo completo. O exemplo chama a função count_primes e a função 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, em seguida, execute o seguinte comando em uma janela do 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 lambda, um ponteiro de função ou um objeto de função. Cada função de filtro assume uma das seguintes formas:
bool (T)
bool (T const &)
Para eliminar a cópia desnecessária de dados, use o segundo formulário quando tiver um tipo agregado que é transmitido por valor.
Ver também
Biblioteca de agentes assíncronos
Passo a passo: Criando um agente de fluxo de dados
Passo a passo: Criando uma rede Image-Processing
transformador Classe