비동기 메시지 블록

에이전트 라이브러리는 스레드로부터 안전한 방식으로 애플리케이션 구성 요소 간에 메시지를 전파할 수 있는 몇 가지 메시지 블록 형식을 제공합니다. 이러한 메시지 블록 형식은 동시성::send, concurrency::asend, concurrency::receive 및 concurrency::try_receive 같은 다양한 메시지 전달 루틴과 함께 사용되는 경우가 많습니다. 에이전트 라이브러리에서 정의한 메시지 전달 루틴에 대한 자세한 내용은 메시지 전달 함수를 참조 하세요.

섹션

이 항목에는 다음과 같은 섹션이 포함되어 있습니다.

소스 및 대상

원본과 대상은 메시지 전달에 중요한 두 참가자입니다. 원본메시지를 보내는 통신의 엔드포인트를 나타냅니다. 대상메시지를 수신하는 통신의 엔드포인트를 나타냅니다. 원본을 읽은 엔드포인트로 간주하고 대상을 작성하는 엔드포인트로 간주할 수 있습니다. 애플리케이션은 원본과 대상을 함께 연결하여 메시징 네트워크를 형성합니다.

에이전트 라이브러리는 두 가지 추상 클래스를 사용하여 원본과 대상 을 나타냅니다. 동시성::ISource동시성::ITarget. 원본으로 작동하는 메시지 블록 형식은 파생 ISource됩니다. 대상 역할을 하는 메시지 블록 형식은 파생 ITarget됩니다. 원본 및 대상 역할을 하는 메시지 블록 형식은 둘 다 ISource 에서 파생됩니다 ITarget.

[맨 위로 이동]

메시지 전파

메시지 전파 는 한 구성 요소에서 다른 구성 요소로 메시지를 보내는 동작입니다. 메시지 블록에 메시지가 제공되면 해당 메시지를 수락, 거절 또는 연기할 수 있습니다. 모든 메시지 블록 유형은 다양한 방식으로 메시지를 저장하고 전송합니다. 예를 들어 클래스는 unbounded_buffer 무제한의 메시지를 저장하고, overwrite_buffer 클래스는 한 번에 하나의 메시지를 저장하고, 변환기 클래스는 각 메시지의 변경된 버전을 저장합니다. 이러한 메시지 블록 유형은 이 문서의 뒷부분에 자세히 설명되어 있습니다.

메시지 블록이 메시지를 수락하면 필요에 따라 작업을 수행할 수 있으며 메시지 블록이 원본인 경우 결과 메시지를 네트워크의 다른 구성원에게 전달합니다. 메시지 블록은 필터 함수를 사용하여 수신하지 않으려는 메시지를 거부할 수 있습니다. 필터는 이 항목의 뒷부분에 있는 메시지 필터링 섹션 에 자세히 설명되어 있습니다. 메시지를 연기하는 메시지 블록은 해당 메시지를 예약하고 나중에 사용할 수 있습니다. 메시지 예약은 이 항목의 뒷부분에 있는 메시지 예약 섹션 에 자세히 설명되어 있습니다.

에이전트 라이브러리를 사용하면 메시지 블록이 메시지를 비동기적으로 또는 동기적으로 전달할 수 있습니다. 예를 들어 함수를 사용하여 send 메시지 블록에 메시지를 동기적으로 전달하는 경우 런타임은 대상 블록이 메시지를 수락하거나 거부할 때까지 현재 컨텍스트를 차단합니다. 예를 들어 함수를 사용하여 asend 메시지를 메시지 블록에 비동기적으로 전달하는 경우 런타임은 대상에 메시지를 제공하고, 대상이 메시지를 수락하면 런타임은 메시지를 수신자로 전파하는 비동기 작업을 예약합니다. 런타임은 간단한 작업을 사용하여 협조적인 방식으로 메시지를 전파합니다. 간단한 작업에 대한 자세한 내용은 작업 스케줄러를 참조 하세요.

애플리케이션은 원본과 대상을 함께 연결하여 메시징 네트워크를 형성합니다. 일반적으로 네트워크를 연결하고 호출 send 하거나 asend 네트워크에 데이터를 전달합니다. 원본 메시지 블록을 대상에 연결하려면 동시성::ISource::link_target 메서드를 호출합니다. 대상에서 소스 블록의 연결을 끊려면 동시성::ISource::unlink_target 메서드를 호출합니다. 모든 대상에서 소스 블록의 연결을 끊려면 동시성::ISource::unlink_targets 메서드를 호출합니다. 미리 정의된 메시지 블록 유형 중 하나가 범위를 벗어나거나 제거되면 대상 블록에서 자동으로 연결이 끊어집니다. 일부 메시지 블록 유형은 쓸 수 있는 최대 대상 수를 제한합니다. 다음 섹션에서는 미리 정의된 메시지 블록 형식에 적용되는 제한 사항에 대해 설명합니다.

[맨 위로 이동]

메시지 블록 형식 개요

다음 표에서는 중요한 메시지 블록 형식의 역할을 간략하게 설명합니다.

unbounded_buffer
메시지 큐를 저장합니다.

overwrite_buffer
여러 번 쓰고 읽을 수 있는 하나의 메시지를 저장합니다.

single_assignment
한 번에 쓰고 여러 번 읽을 수 있는 하나의 메시지를 저장합니다.

call
메시지를 받을 때 작업을 수행합니다.

변압기
데이터를 수신하고 해당 작업의 결과를 다른 대상 블록으로 보낼 때 작업을 수행합니다. 클래스는 transformer 다양한 입력 및 출력 형식에 따라 작동할 수 있습니다.

choice
원본 집합에서 사용 가능한 첫 번째 메시지를 선택합니다.

조인 및 다중 형식 조인
모든 메시지가 원본 집합에서 수신될 때까지 기다린 다음 메시지를 다른 메시지 블록에 대한 하나의 메시지로 결합합니다.

타이머
정기적으로 대상 블록에 메시지를 보냅니다.

이러한 메시지 블록 형식에는 다양한 상황에서 유용하게 사용할 수 있는 다양한 특성이 있습니다. 몇 가지 특징은 다음과 같습니다.

  • 전파 유형: 메시지 블록이 데이터 원본, 데이터 수신자 또는 둘 다의 역할을 하는지 여부입니다.

  • 메시지 순서 지정: 메시지 블록이 메시지를 보내거나 받는 원래 순서와 기본 여부입니다. 미리 정의된 각 메시지 블록 유형은 메시지를 보내거나 받는 원래 순서를 기본.

  • 원본 수: 메시지 블록에서 읽을 수 있는 최대 원본 수입니다.

  • 대상 수: 메시지 블록이 쓸 수 있는 최대 대상 수입니다.

다음 표에서는 이러한 특성이 다양한 메시지 블록 형식과 어떻게 관련되는지 보여 줍니다.

메시지 블록 유형 전파 형식(원본, 대상 또는 둘 다) 메시지 순서 지정(순서가 지정되거나 순서가 지정되지 않음) 원본 수 대상 수
unbounded_buffer 모두 주문됨 제한 없음 제한 없음
overwrite_buffer 모두 주문됨 제한 없음 제한 없음
single_assignment 모두 주문됨 제한 없음 제한 없음
call 대상 주문됨 제한 없음 해당 없음
transformer 모두 주문됨 제한 없음 1
choice 모두 주문됨 10 1
join 모두 주문됨 제한 없음 1
multitype_join 모두 주문됨 10 1
timer 원본 해당 없음 해당 없음 1

다음 섹션에서는 메시지 블록 형식에 대해 자세히 설명합니다.

[맨 위로 이동]

unbounded_buffer 클래스

동시성::unbounded_buffer 클래스는 범용 비동기 메시징 구조를 나타냅니다. 이 클래스는 여러 소스가 기록하거나 여러 대상이 읽을 수 있는 메시지의 FIFO(선입 선출) 큐를 저장합니다. 대상이 개체에서 unbounded_buffer 메시지를 받으면 해당 메시지가 메시지 큐에서 제거됩니다. 따라서 개체에 unbounded_buffer 여러 대상이 있을 수 있지만 각 메시지를 받는 대상은 하나뿐입니다. unbounded_buffer 클래스는 여러 메시지를 다른 구성 요소에 전달하려고 할 때 유용하고 해당 구성 요소는 각 메시지를 수신해야 합니다.

예시

다음 예제에서는 클래스로 작업 unbounded_buffer 하는 방법의 기본 구조를 보여줍니다. 이 예제에서는 개체에 unbounded_buffer 세 개의 값을 보낸 다음 동일한 개체에서 해당 값을 다시 읽습니다.

// unbounded_buffer-structure.cpp
// compile with: /EHsc
#include <agents.h>
#include <iostream>

using namespace concurrency;
using namespace std;

int wmain()
{
   // Create an unbounded_buffer object that works with
   // int data.
   unbounded_buffer<int> items;

   // Send a few items to the unbounded_buffer object.
   send(items, 33);
   send(items, 44);
   send(items, 55);

   // Read the items from the unbounded_buffer object and print
   // them to the console.
   wcout << receive(items) << endl;
   wcout << receive(items) << endl;
   wcout << receive(items) << endl;
}

이 예제는 다음과 같은 출력을 생성합니다.

334455

클래스를 사용하는 unbounded_buffer 방법을 보여 주는 전체 예제는 방법: 다양한 생산자-소비자 패턴 구현을 참조 하세요.

[맨 위로 이동]

overwrite_buffer 클래스

동시성::overwrite_buffer 클래스는 개체가 하나의 메시지만 저장한다는 점을 overwrite_buffer 제외하고 클래스와 유사 unbounded_buffer 합니다. 또한 대상이 개체에서 overwrite_buffer 메시지를 받으면 해당 메시지는 버퍼에서 제거되지 않습니다. 따라서 여러 대상이 하나의 메시지 복사본을 수신합니다.

overwrite_buffer 클래스는 여러 메시지를 다른 구성 요소에 전달하려는 경우 유용하지만 해당 구성 요소에는 최신 값만 필요합니다. 이 클래스는 여러 구성 요소에 메시지를 브로드캐스트하려고 할 때도 유용합니다.

예시

다음 예제에서는 클래스로 작업 overwrite_buffer 하는 방법의 기본 구조를 보여줍니다. 다음은 개체에 overwrite _buffer 세 개의 값을 보낸 다음 같은 개체에서 현재 값을 세 번 읽는 예제입니다. 이 예제는 클래스의 예제와 unbounded_buffer 비슷합니다. 그러나 클래스는 overwrite_buffer 하나의 메시지만 저장합니다. 또한 런타임은 읽은 후 개체에서 overwrite_buffer 메시지를 제거하지 않습니다.

// overwrite_buffer-structure.cpp
// compile with: /EHsc
#include <agents.h>
#include <iostream>

using namespace concurrency;
using namespace std;

int wmain()
{
   // Create an overwrite_buffer object that works with
   // int data.
   overwrite_buffer<int> item;

   // Send a few items to the overwrite_buffer object.
   send(item, 33);
   send(item, 44);
   send(item, 55);

   // Read the current item from the overwrite_buffer object and print
   // it to the console three times.
   wcout << receive(item) << endl;
   wcout << receive(item) << endl;
   wcout << receive(item) << endl;
}

이 예제는 다음과 같은 출력을 생성합니다.

555555

클래스를 사용하는 overwrite_buffer 방법을 보여 주는 전체 예제는 방법: 다양한 생산자-소비자 패턴 구현을 참조 하세요.

[맨 위로 이동]

single_assignment 클래스

동시성::single_assignment 클래스는 개체를 overwrite_buffer 한 번만 쓸 수 있다는 점을 single_assignment 제외하고 클래스와 유사합니다. overwrite_buffer 클래스처럼 대상이 single_assignment 개체에서 메시지를 수신할 때 해당 메시지는 해당 개체에서 제거되지 않습니다. 따라서 여러 대상이 하나의 메시지 복사본을 수신합니다. 이 single_assignment 클래스는 하나의 메시지를 여러 구성 요소에 브로드캐스트하려는 경우에 유용합니다.

예시

다음 예제에서는 클래스로 작업 single_assignment 하는 방법의 기본 구조를 보여줍니다. 다음은 개체에 single_assignment 세 개의 값을 보낸 다음 같은 개체에서 현재 값을 세 번 읽는 예제입니다. 이 예제는 클래스의 예제와 overwrite_buffer 비슷합니다. 두 single_assignment 클래스 모두 overwrite_buffer 단일 메시지를 저장하지만 클래스는 single_assignment 한 번만 작성할 수 있습니다.

// single_assignment-structure.cpp
// compile with: /EHsc
#include <agents.h>
#include <iostream>

using namespace concurrency;
using namespace std;

int wmain()
{
   // Create an single_assignment object that works with
   // int data.
   single_assignment<int> item;

   // Send a few items to the single_assignment object.
   send(item, 33);
   send(item, 44);
   send(item, 55);

   // Read the current item from the single_assignment object and print
   // it to the console three times.
   wcout << receive(item) << endl;
   wcout << receive(item) << endl;
   wcout << receive(item) << endl;
}

이 예제는 다음과 같은 출력을 생성합니다.

333333

클래스를 사용하는 single_assignment 방법을 보여 주는 전체 예제는 연습: 선물 구현을 참조 하세요.

[맨 위로 이동]

call 클래스

동시성::call 클래스는 데이터를 받을 때 작업 함수를 수행하는 메시지 수신자 역할을 합니다. 이 작업 함수는 람다 식, 함수 개체 또는 함수 포인터일 수 있습니다. 개체는 call 메시지를 보내는 다른 구성 요소와 병렬로 작동하므로 일반 함수 호출과 다르게 동작합니다. 개체가 call 메시지를 받을 때 작업을 수행하는 경우 해당 메시지를 큐에 추가합니다. 모든 call 개체는 큐에 대기 중인 메시지를 받은 순서대로 처리합니다.

예시

다음 예제에서는 클래스로 작업 call 하는 방법의 기본 구조를 보여줍니다. 이 예제에서는 콘솔에 call 받는 각 값을 인쇄하는 개체를 만듭니다. 그런 다음 개체에 세 개의 값을 call 보냅니다. 개체가 call 별도의 스레드에서 메시지를 처리하므로 이 예제에서는 카운터 변수와 이벤트 개체를 사용하여 함수가 반환되기 전에 wmain 개체가 call 모든 메시지를 처리하도록 합니다.

// call-structure.cpp
// compile with: /EHsc
#include <agents.h>
#include <iostream>

using namespace concurrency;
using namespace std;

int wmain()
{
   // An event that is set when the call object receives all values.
   event received_all;

   // Counts the 
   long receive_count = 0L;
   long max_receive_count = 3L;

   // Create an call object that works with int data.
   call<int> target([&received_all,&receive_count,max_receive_count](int n) {
      // Print the value that the call object receives to the console.
      wcout << n << endl;
      
      // Set the event when all messages have been processed.
      if (++receive_count == max_receive_count)
         received_all.set();
   });

   // Send a few items to the call object.
   send(target, 33);
   send(target, 44);
   send(target, 55);

   // Wait for the call object to process all items.
   received_all.wait();
}

이 예제는 다음과 같은 출력을 생성합니다.

334455

클래스를 사용하는 call 방법을 보여 주는 전체 예제는 방법: 호출 및 변환기 클래스에 작업 함수 제공을 참조 하세요.

[맨 위로 이동]

transformer 클래스

동시성::변환기 클래스는 메시지 수신자 및 메시지 보낸 사람 역할을 합니다. 클래스는 transformer 데이터를 받을 때 사용자 정의 작업 함수를 수행하기 때문에 클래스와 유사 call 합니다. 그러나 클래스는 transformer 작업 함수의 결과를 수신자 개체에 보냅니다. 개체와 call 마찬가지로 개체는 transformer 메시지를 보내는 다른 구성 요소와 병렬로 작동합니다. 개체가 transformer 메시지를 받을 때 작업을 수행하는 경우 해당 메시지를 큐에 추가합니다. 모든 transformer 개체는 큐에 대기 중인 메시지를 받은 순서대로 처리합니다.

클래스는 transformer 메시지를 한 대상에 보냅니다. 생성자의 NULL매개 변수를 _PTarget 설정하는 경우 나중에 동시성::link_target 메서드를 호출하여 대상을 지정할 수 있습니다.

에이전트 라이브러리에서 제공하는 다른 모든 비동기 메시지 블록 형식과 달리 클래스 transformer 는 다른 입력 및 출력 형식에 따라 작동할 수 있습니다. 한 형식에서 다른 형식으로 데이터를 변환하는 이 기능은 클래스를 transformer 여러 동시 네트워크의 핵심 구성 요소로 만듭니다. 또한 개체의 transformer 작업 함수에 더 세분화된 병렬 기능을 추가할 수 있습니다.

예시

다음 예제에서는 클래스로 작업 transformer 하는 방법의 기본 구조를 보여줍니다. 이 예제에서는 값을 출력으로 생성하기 위해 각 입력 int 값을 0.33으로 배수하는 개체를 double 만듭니다transformer. 그런 다음, 동일한 transformer 개체에서 변환된 값을 받아 콘솔에 출력합니다.

// transformer-structure.cpp
// compile with: /EHsc
#include <agents.h>
#include <iostream>

using namespace concurrency;
using namespace std;

int wmain()
{
   // Create an transformer object that receives int data and 
   // sends double data.
   transformer<int, double> third([](int n) {
      // Return one-third of the input value.
      return n * 0.33;
   });

   // Send a few items to the transformer object.
   send(third, 33);
   send(third, 44);
   send(third, 55);

   // Read the processed items from the transformer object and print
   // them to the console.
   wcout << receive(third) << endl;
   wcout << receive(third) << endl;
   wcout << receive(third) << endl;
}

이 예제는 다음과 같은 출력을 생성합니다.

10.8914.5218.15

클래스를 사용하는 transformer 방법을 보여 주는 전체 예제는 방법: 데이터 파이프라인에서 변환기 사용 방법을 참조하세요.

[맨 위로 이동]

choice 클래스

동시성::choice 클래스는 원본 집합에서 사용 가능한 첫 번째 메시지를 선택합니다. 이 클래스는 choice 데이터 흐름 메커니즘 대신 제어 흐름 메커니즘을 나타냅니다(토픽 비동기 에이전트 라이브러리 는 데이터 흐름과 제어 흐름 간의 차이점을 설명함).

선택 개체에서 읽는 것은 매개 변수가 설정된 경우 Windows API 함수 WaitForMultipleObjects 를 호출하는 bWaitAll 것과 유사합니다 FALSE. 그러나 클래스는 choice 외부 동기화 개체 대신 이벤트 자체에 데이터를 바인딩합니다.

일반적으로 동시성::receive 함수와 함께 클래스를 사용하여 choice 애플리케이션에서 제어 흐름을 구동합니다. 형식이 choice 다른 메시지 버퍼 중에서 선택해야 하는 경우 클래스를 사용합니다. 동일한 형식의 single_assignment 메시지 버퍼 중에서 선택해야 하는 경우 클래스를 사용합니다.

선택한 메시지를 확인할 수 있으므로 원본을 개체에 choice 연결하는 순서가 중요합니다. 예를 들어 이미 메시지가 포함된 여러 메시지 버퍼를 개체에 연결하는 경우를 choice 고려합니다. 개체는 choice 연결된 첫 번째 원본에서 메시지를 선택합니다. 모든 원본을 연결한 후 개체는 choice 각 원본이 메시지를 받는 순서를 유지합니다.

예시

다음 예제에서는 클래스로 작업 choice 하는 방법의 기본 구조를 보여줍니다. 이 예제에서는 동시성::make_choice 함수를 사용하여 세 개의 메시지 블록 중에서 choice 선택하는 개체를 만듭니다. 그런 다음, 다양한 피보나치 숫자를 계산하고 각 결과를 다른 메시지 블록에 저장합니다. 그런 다음, 먼저 완료된 작업을 기반으로 하는 메시지를 콘솔에 출력합니다.

// choice-structure.cpp
// compile with: /EHsc
#include <agents.h>
#include <ppl.h>
#include <iostream>

using namespace concurrency;
using namespace std;

// Computes the nth Fibonacci number.
// This function illustrates a lengthy operation and is therefore
// not optimized for performance.
int fibonacci(int n)
{
   if (n < 2)
      return n;
   return fibonacci(n-1) + fibonacci(n-2);
}

int wmain()
{
   // Although the following thee message blocks are written to one time only, 
   // this example illustrates the fact that the choice class works with 
   // different message block types.

   // Holds the 35th Fibonacci number.
   single_assignment<int> fib35;
   // Holds the 37th Fibonacci number.
   overwrite_buffer<int> fib37;
   // Holds half of the 42nd Fibonacci number.
   unbounded_buffer<double> half_of_fib42;   

   // Create a choice object that selects the first single_assignment 
   // object that receives a value.
   auto select_one = make_choice(&fib35, &fib37, &half_of_fib42);

   // Execute a few lengthy operations in parallel. Each operation sends its 
   // result to one of the single_assignment objects.
   parallel_invoke(
      [&fib35] { send(fib35, fibonacci(35)); },
      [&fib37] { send(fib37, fibonacci(37)); },
      [&half_of_fib42] { send(half_of_fib42, fibonacci(42) * 0.5); }
   );

   // Print a message that is based on the operation that finished first.
   switch (receive(select_one))
   {
   case 0:
      wcout << L"fib35 received its value first. Result = " 
            << receive(fib35) << endl;
      break;
   case 1:
      wcout << L"fib37 received its value first. Result = " 
            << receive(fib37) << endl;
      break;
   case 2:
      wcout << L"half_of_fib42 received its value first. Result = " 
            << receive(half_of_fib42) << endl;
      break;
   default:
      wcout << L"Unexpected." << endl;
      break;
   }
}

이 예제에서는 다음 샘플 출력을 생성합니다.

fib35 received its value first. Result = 9227465

35번째 피보나치 수를 계산하는 작업이 먼저 완료되도록 보장되지 않으므로 이 예제의 출력은 다를 수 있습니다.

이 예제에서는 동시성::p arallel_invoke 알고리즘을 사용하여 피보나치 숫자를 병렬로 계산합니다. 자세한 parallel_invoke내용은 병렬 알고리즘을 참조 하세요.

클래스를 사용하는 choice 방법을 보여 주는 전체 예제는 방법: 완료된 작업 중 선택

[맨 위로 이동]

join 및 multitype_join 클래스

동시성::조인동시성::multitype_join 클래스를 사용하면 원본 집합의 각 멤버가 메시지를 받을 때까지 기다릴 수 있습니다. 클래스는 join 공통 메시지 형식을 가진 소스 개체에 대해 작동합니다. 이 클래스는 multitype_join 메시지 유형이 다를 수 있는 소스 개체에 대해 작동합니다.

또는 개체에서 join 읽는 것은 매개 변수가 설정된 경우 Windows API 함수 WaitForMultipleObjectsbWaitAll 호출하는 것과 유사합니다TRUE.multitype_join 그러나 개체와 multitype_join 마찬가지로 choice 개체 join 는 외부 동기화 개체 대신 이벤트 자체에 데이터를 바인딩하는 이벤트 메커니즘을 사용합니다.

개체에서 읽는 것은 join std::vector 개체를 생성합니다. 개체에서 읽는 것은 multitype_join std::tuple 개체를 생성합니다. 요소는 해당 소스 버퍼가 또는 multitype_join 개체에 연결된 것과 동일한 순서로 이러한 개체에 join 나타납니다. 원본 버퍼를 연결 join 하거나 multitype_join 개체에 연결하는 순서는 결과 vector 또는 tuple 개체의 요소 순서와 연결되므로 조인에서 기존 원본 버퍼의 연결을 해제하지 않는 것이 좋습니다. 이렇게 하면 지정되지 않은 동작이 발생할 수 있습니다.

탐욕과 비욕적인 조인 비교

multitype_join 클래스는 join 탐욕과 비 탐욕 조인의 개념을 지원합니다. greedy 조은 모든 메시지를 사용할 수 있게 될 때까지 메시지를 사용할 수 있게 됨에 따라 각 원본의 메시지를 수락합니다. 욕심이 없는 조인은 두 단계로 메시지를 받습니다. 첫째, 비욕심 조인은 각 원본에서 메시지가 제공될 때까지 기다립니다. 둘째, 모든 원본 메시지를 사용할 수 있게 된 후에는 욕심이 없는 조인이 각 메시지를 예약하려고 시도합니다. 각 메시지를 예약할 수 있는 경우 모든 메시지를 사용하고 대상에 전파합니다. 그렇지 않으면 메시지 예약을 해제하거나 취소하고 각 원본이 메시지를 받을 때까지 다시 기다립니다.

Greedy 조인은 메시지를 즉시 수락하기 때문에 비욕심 조인보다 성능이 우수합니다. 그러나 드문 경우에서 탐욕스러운 조인은 교착 상태로 이어질 수 있습니다. 하나 이상의 공유 원본 개체를 포함하는 여러 조인이 있는 경우 비욕적인 조인을 사용합니다.

예시

다음 예제에서는 클래스로 작업 join 하는 방법의 기본 구조를 보여줍니다. 이 예제에서는 동시성::make_join 함수를 사용하여 single_assignment 개체에서 수신하는 개체를 만듭니 join 다. 이 예제에서는 다양한 피보나치 숫자를 계산하고 각 결과를 다른 single_assignment 개체에 저장한 다음 개체가 보유하는 각 결과를 콘솔에 join 출력합니다. 이 예제는 클래스가 모든 원본 메시지 블록이 메시지를 받을 때까지 대기한다는 점을 join 제외하고 클래스의 예제 choice 와 비슷합니다.

// join-structure.cpp
// compile with: /EHsc
#include <agents.h>
#include <ppl.h>
#include <iostream>

using namespace concurrency;
using namespace std;

// Computes the nth Fibonacci number.
// This function illustrates a lengthy operation and is therefore
// not optimized for performance.
int fibonacci(int n)
{
   if (n < 2)
      return n;
   return fibonacci(n-1) + fibonacci(n-2);
}

int wmain()
{
   // Holds the 35th Fibonacci number.
   single_assignment<int> fib35;
   // Holds the 37th Fibonacci number.
   single_assignment<int> fib37;
   // Holds half of the 42nd Fibonacci number.
   single_assignment<double> half_of_fib42;   

   // Create a join object that selects the values from each of the
   // single_assignment objects.
   auto join_all = make_join(&fib35, &fib37, &half_of_fib42);

   // Execute a few lengthy operations in parallel. Each operation sends its 
   // result to one of the single_assignment objects.
   parallel_invoke(
      [&fib35] { send(fib35, fibonacci(35)); },
      [&fib37] { send(fib37, fibonacci(37)); },
      [&half_of_fib42] { send(half_of_fib42, fibonacci(42) * 0.5); }
   );

   auto result = receive(join_all);
   wcout << L"fib35 = " << get<0>(result) << endl;
   wcout << L"fib37 = " << get<1>(result) << endl;
   wcout << L"half_of_fib42 = " << get<2>(result) << endl;
}

이 예제는 다음과 같은 출력을 생성합니다.

fib35 = 9227465fib37 = 24157817half_of_fib42 = 1.33957e+008

이 예제에서는 동시성::p arallel_invoke 알고리즘을 사용하여 피보나치 숫자를 병렬로 계산합니다. 자세한 parallel_invoke내용은 병렬 알고리즘을 참조 하세요.

클래스를 사용하는 join 방법을 보여 주는 전체 예제는 방법: 완료된 작업 중 선택 및 연습: 조인을 사용하여 교착 상태 방지를 참조하세요.

[맨 위로 이동]

timer 클래스

concurrency::timer 클래스 는 메시지 소스 역할을 합니다. timer 지정된 기간이 경과한 후 개체가 대상에 메시지를 보냅니다. 이 timer 클래스는 메시지 전송을 지연해야 하거나 정기적으로 메시지를 보내려는 경우에 유용합니다.

클래스는 timer 메시지를 하나의 대상에만 보냅니다. 생성자의 매개 변수를 NULL설정하는 _PTarget 경우 나중에 동시성::ISource::link_target 메서드를 호출하여 대상을 지정할 수 있습니다.

개체를 timer 반복하거나 반복하지 않을 수 있습니다. 반복 타이머를 만들려면 생성자를 호출할 때 매개 변수를 전달 true_Repeating 합니다. 그렇지 않으면 매개 변수를 _Repeating 전달 false 하여 반복하지 않는 타이머를 만듭니다. 타이머가 반복되면 각 간격 후에 동일한 메시지를 대상에 보냅니다.

에이전트 라이브러리는 시작되지 않은 상태로 개체를 만듭니다 timer . 타이머 개체를 시작하려면 동시성::timer::start 메서드를 호출합니다. 개체를 timer 중지하려면 개체를 삭제하거나 동시성::timer::stop 메서드를 호출합니다. 반복 타이머를 일시 중지하려면 동시성::timer::p ause 메서드를 호출합니다.

예시

다음 예제에서는 클래스로 작업 timer 하는 방법의 기본 구조를 보여줍니다. 이 예제에서는 사용 및 call 개체를 사용하여 timer 긴 작업의 진행률을 보고합니다.

// timer-structure.cpp
// compile with: /EHsc
#include <agents.h>
#include <iostream>

using namespace concurrency;
using namespace std;

// Computes the nth Fibonacci number.
// This function illustrates a lengthy operation and is therefore
// not optimized for performance.
int fibonacci(int n)
{
   if (n < 2)
      return n;
   return fibonacci(n-1) + fibonacci(n-2);
}

int wmain()
{
   // Create a call object that prints characters that it receives 
   // to the console.
   call<wchar_t> print_character([](wchar_t c) {
      wcout << c;
   });

   // Create a timer object that sends the period (.) character to 
   // the call object every 100 milliseconds.
   timer<wchar_t> progress_timer(100u, L'.', &print_character, true);

   // Start the timer.
   wcout << L"Computing fib(42)";
   progress_timer.start();

   // Compute the 42nd Fibonacci number.
   int fib42 = fibonacci(42);

   // Stop the timer and print the result.
   progress_timer.stop();
   wcout << endl << L"result is " << fib42 << endl;
}

이 예제에서는 다음 샘플 출력을 생성합니다.

Computing fib(42)..................................................result is 267914296

클래스를 사용하는 timer 방법을 보여 주는 전체 예제는 방법: 일반 간격으로 메시지 보내기를 참조하세요.

[맨 위로 이동]

메시지 필터링

메시지 블록 개체를 만들 때 메시지 블록이 메시지를 수락하거나 거부하는지 여부를 결정하는 필터 함수를 제공할 수 있습니다. 필터 함수는 메시지 블록이 특정 값만 수신하도록 보장하는 유용한 방법입니다.

다음 예제에서는 필터 함수를 사용하여 짝수만 허용하는 개체를 만드는 unbounded_buffer 방법을 보여 줍니다. 개체는 unbounded_buffer 홀수 값을 거부하므로 홀수 값을 대상 블록에 전파하지 않습니다.

// filter-function.cpp
// compile with: /EHsc
#include <agents.h>
#include <iostream>

using namespace concurrency;
using namespace std;

int wmain()
{
   // Create an unbounded_buffer object that uses a filter
   // function to accept only even numbers.
   unbounded_buffer<int> accept_evens(
      [](int n) {
         return (n%2) == 0;
      });

   // Send a few values to the unbounded_buffer object.
   unsigned int accept_count = 0;
   for (int i = 0; i < 10; ++i)
   {
      // The asend function returns true only if the target
      // accepts the message. This enables us to determine
      // how many elements are stored in the unbounded_buffer
      // object.
      if (asend(accept_evens, i))
      {
         ++accept_count;
      }
   }

   // Print to the console each value that is stored in the 
   // unbounded_buffer object. The unbounded_buffer object should
   // contain only even numbers.
   while (accept_count > 0)
   {
      wcout << receive(accept_evens) << L' ';
      --accept_count;
   }
}

이 예제는 다음과 같은 출력을 생성합니다.

0 2 4 6 8

필터 함수는 람다 함수, 함수 포인터 또는 함수 개체일 수 있습니다. 모든 필터 함수는 다음 형식 중 하나를 사용합니다.

bool (T)
bool (T const &)

불필요한 데이터 복사를 제거하려면 값으로 전파되는 집계 형식이 있는 경우 두 번째 양식을 사용합니다.

메시지 필터링은 구성 요소가 데이터를 받을 때 계산을 수행하는 데이터 흐름 프로그래밍 모델을 지원합니다. 필터 함수를 사용하여 메시지를 전달하는 네트워크의 데이터 흐름을 제어하는 예제는 방법: 메시지 블록 필터 사용, 연습: 데이터 흐름 에이전트 만들기 및 연습: 이미지 처리 네트워크 만들기를 참조하세요.

[맨 위로 이동]

메시지 예약

메시지 예약 을 사용하면 메시지 블록에서 나중에 사용할 메시지를 예약할 수 있습니다. 일반적으로 메시지 예약은 직접 사용되지 않습니다. 그러나 메시지 예약을 이해하면 미리 정의된 메시지 블록 유형 중 일부의 동작을 더 잘 이해할 수 있습니다.

욕심이 없는 조인과 탐욕스러운 조인을 고려해 보세요. 둘 다 메시지 예약을 사용하여 나중에 사용할 메시지를 예약합니다. 앞에서 설명한 비욕심 조인은 두 단계로 메시지를 받습니다. 첫 번째 단계에서는 욕심이 join 없는 개체가 각 원본이 메시지를 받을 때까지 기다립니다. 그런 다음, 욕심이 없는 조인이 각 메시지를 예약하려고 시도합니다. 각 메시지를 예약할 수 있는 경우 모든 메시지를 사용하고 대상에 전파합니다. 그렇지 않으면 메시지 예약을 해제하거나 취소하고 각 원본이 메시지를 받을 때까지 다시 기다립니다.

여러 원본에서 입력 메시지를 읽는 greedy 조인은 메시지 예약을 사용하여 각 원본에서 메시지를 받기 위해 기다리는 동안 추가 메시지를 읽습니다. 예를 들어 메시지 블록 AB에서 메시지를 수신하는 greedy 조인을 고려합니다. greedy 조인이 B에서 두 개의 메시지를 수신하지만 아직 메시지를 A받지 못한 경우 greedy 조인은 두 번째 메시지의 B고유 메시지 식별자를 저장합니다. greedy 조인이 메시지를 수신하고 이러한 메시지를 A 전파한 후 저장된 메시지 식별자를 사용하여 두 번째 메시지를 B 계속 사용할 수 있는지 확인합니다.

사용자 지정 메시지 블록 형식을 구현할 때 메시지 예약을 사용할 수 있습니다. 사용자 지정 메시지 블록 유형을 만드는 방법에 대한 예제는 연습: 사용자 지정 메시지 블록 만들기를 참조하세요.

[맨 위로 이동]

참고 항목

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