방법: 메시지 블록 필터 사용
이 문서에서는 필터 함수를 사용하여 비동기 메시지 블록이 해당 메시지의 페이로드를 기반으로 메시지를 수락하거나 거부할 수 있도록 하는 방법을 보여 줍니다.
동시성::unbounded_buffer, 동시성::call 또는 concurrency::transformer와 같은 메시지 블록 개체를 만들 때 메시지 블록이 메시지를 수락하거나 거부하는지 여부를 결정하는 필터 함수를 제공할 수 있습니다. 필터 함수는 메시지 블록이 특정 값만 수신하도록 보장하는 유용한 방법입니다.
필터 함수는 메시지 블록을 연결하여 데이터 흐름 네트워크를 형성할 수 있기 때문에 중요합니다. 데이터 흐름 네트워크에서 메시지 블록은 특정 조건을 충족하는 메시지만 처리하여 데이터 흐름을 제어합니다. 이를 조건문, 루프 등과 같은 제어 구조를 사용하여 데이터 흐름이 규제되는 제어 흐름 모델과 비교합니다.
이 문서에서는 메시지 필터를 사용하는 방법에 대한 기본 예제를 제공합니다. 메시지 필터 및 데이터 흐름 모델을 사용하여 메시지 블록을 연결하는 추가 예제는 연습: 데이터 흐름 에이전트 만들기 및 연습: 이미지 처리 네트워크 만들기를 참조하세요.
예: count_primes 함수
들어오는 메시지를 필터링하지 않는 메시지 블록의 기본 사용을 보여 주는 다음 함수 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_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
모든 메시지를 처리합니다. 따라서 이전 예제에서는 보내는 메시지 수와 동일한 수의 메시지를 받아야 합니다. 이 예제에서는 동시성::send 함수의 결과를 사용하여 개체에서 transformer
받을 메시지 수를 결정합니다. 이 함수는 send
메시지 버퍼가 메시지를 수락하고 false
메시지 버퍼가 메시지를 거부할 때 반환 true
됩니다. 따라서 메시지 버퍼가 메시지를 수락하는 횟수는 소수 수와 일치합니다.
예: 완료된 메시지 블록 필터 코드 샘플
다음 코드에서는 전체 예제를 보여 줍니다. 이 예제에서는 함수와 함수를 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
*/
}
코드 컴파일
예제 코드를 복사하여 Visual Studio 프로젝트에 붙여넣거나 이름이 지정된 primes-filter.cpp
파일에 붙여넣은 다음 Visual Studio 명령 프롬프트 창에서 다음 명령을 실행합니다.
cl.exe /EHsc primes-filter.cpp
강력한 프로그래밍
필터 함수는 람다 함수, 함수 포인터 또는 함수 개체일 수 있습니다. 모든 필터 함수는 다음 형식 중 하나를 사용합니다.
bool (T)
bool (T const &)
불필요한 데이터 복사를 제거하려면 값으로 전송되는 집계 형식이 있는 경우 두 번째 양식을 사용합니다.
참고 항목
비동기 에이전트 라이브러리
연습: 데이터 흐름 에이전트 만들기
연습: 이미지 처리 네트워크 만들기
transformer 클래스