방법: 메시지 블록 필터 사용

이 문서에서는 필터 함수를 사용하여 비동기 메시지 블록에서 해당 메시지의 페이로드를 기준으로 메시지를 수락하거나 거부할 수 있도록 설정하는 방법을 보여 줍니다.

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, 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_each(primes.begin(), primes.end(), [](unsigned long prime) {
      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;
      },
      NULL,      
      [](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, 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, 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_each(primes.begin(), primes.end(), [](unsigned long prime) {
      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;
      },
      NULL,      
      [](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, 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);
}

이 예제의 결과는 다음과 같습니다.

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 프로젝트 또는 primes-filter.cpp 파일에 붙여 넣고 Visual Studio 2010 명령 프롬프트 창에서 다음 명령을 실행합니다.

cl.exe /EHsc primes-filter.cpp

강력한 프로그래밍

필터 함수는 람다 함수, 함수 포인터 또는 함수 개체가 될 수 있습니다. 모든 필터 함수는 다음 형식 중 하나로 지정할 수 있습니다.

bool (_Type)
bool (_Type const &)

불필요하게 데이터를 복사하는 일이 없도록 하려면 값으로 전송되는 집계 형식인 경우 두 번째 형식을 사용합니다.

참고 항목

참조

transformer 클래스

개념

비동기 에이전트 라이브러리

기타 리소스

연습: 사용자 지정 데이터 흐름 에이전트 만들기

연습: 이미지 처리 네트워크 만들기