Procedura: Usare il filtro di blocco dei messaggi
Questo documento illustra come usare una funzione di filtro per consentire a un blocco di messaggi asincrono di accettare o rifiutare un messaggio in base al payload di tale messaggio.
Quando si crea un oggetto blocco di messaggi, ad esempio una concorrenza::unbounded_buffer, una concurrency::call o una concurrency::transformer, è possibile fornire una funzione di filtro che determina se il blocco di messaggi accetta o rifiuta un messaggio. Una funzione di filtro è un modo utile per garantire che un blocco di messaggi riceva solo determinati valori.
Le funzioni di filtro sono importanti perché consentono di connettere blocchi di messaggi alle reti di flussi di dati. In una rete di flussi di dati, i blocchi di messaggi controllano il flusso di dati elaborando solo i messaggi che soddisfano criteri specifici. Confrontarlo con il modello di flusso di controllo, in cui il flusso di dati è regolamentato usando strutture di controllo come istruzioni condizionali, cicli e così via.
Questo documento fornisce un esempio di base su come usare un filtro messaggi. Per altri esempi che usano filtri messaggi e il modello di flusso di dati per connettere blocchi di messaggi, vedere Procedura dettagliata: Creazione di un agente di flussi di dati e Procedura dettagliata: Creazione di una rete di elaborazione immagini.
Esempio: funzione count_primes
Si consideri la funzione seguente, count_primes
, che illustra l'utilizzo di base di un blocco di messaggi che non filtra i messaggi in ingresso. Il blocco di messaggi aggiunge numeri primi a un oggetto std::vector . La count_primes
funzione invia diversi numeri al blocco di messaggi, riceve i valori di output dal blocco di messaggi e stampa i numeri primi nella 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;
}
}
L'oggetto transformer
elabora tutti i valori di input, ma richiede solo i valori primi. Anche se l'applicazione può essere scritta in modo che il mittente del messaggio invii solo numeri primi, i requisiti del destinatario del messaggio non possono essere sempre noti.
Esempio: funzione count_primes_filter
La funzione seguente, count_primes_filter
, esegue la stessa attività della count_primes
funzione . Tuttavia, l'oggetto transformer
in questa versione usa una funzione di filtro per accettare solo i valori primi. La funzione che esegue l'azione riceve solo numeri primi; pertanto, non deve chiamare la is_prime
funzione.
Poiché l'oggetto transformer
riceve solo numeri primi, l'oggetto transformer
stesso può contenere i numeri primi. In altre parole, l'oggetto transformer
in questo esempio non è necessario per aggiungere i numeri primi all'oggetto 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;
}
}
L'oggetto transformer
ora elabora solo i valori primi. Nell'esempio precedente, transformer
l'oggetto elabora tutti i messaggi. Pertanto, l'esempio precedente deve ricevere lo stesso numero di messaggi inviati. In questo esempio viene utilizzato il risultato della funzione concurrency::send per determinare il numero di messaggi da ricevere dall'oggetto transformer
. La send
funzione restituisce true
quando il buffer dei messaggi accetta il messaggio e false
quando il buffer dei messaggi rifiuta il messaggio. Pertanto, il numero di volte in cui il buffer dei messaggi accetta il messaggio corrisponde al numero di numeri primi.
Esempio: Esempio di codice di filtro del blocco di messaggi completato
Nel codice seguente viene illustrato l'esempio completo. L'esempio chiama sia la count_primes
funzione che la count_primes_filter
funzione .
// 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
*/
}
Compilazione del codice
Copiare il codice di esempio e incollarlo in un progetto di Visual Studio oppure incollarlo in un file denominato primes-filter.cpp
e quindi eseguire il comando seguente in una finestra del prompt dei comandi di Visual Studio.
cl.exe /EHsc primes-filter.cpp
Programmazione efficiente
Una funzione di filtro può essere una funzione lambda, un puntatore a funzione o un oggetto funzione. Ogni funzione di filtro accetta una delle forme seguenti:
bool (T)
bool (T const &)
Per eliminare la copia non necessaria dei dati, utilizzare il secondo modulo quando si dispone di un tipo di aggregazione trasmesso per valore.
Vedi anche
Libreria di agenti asincroni
Procedura dettagliata: creazione di un agente del flusso di dati
Procedura dettagliata: creazione di una rete per l'elaborazione di immagini
Classe transformer