비동기 메시지 블록
에이전트 라이브러리에서는 스레드로부터 안전한 방식으로 응용 프로그램 구성 요소 간에 메시지를 전파할 수 있도록 하는 몇 가지 메시지 블록 형식을 제공합니다.이러한 메시지 블록 종류는 다양 한 메시지 전달 루틴으로 같은 자주는 concurrency::send, concurrency::asend, concurrency::receive, 및 concurrency::try_receive.에이전트 라이브러리에 정의된 메시지 전달 루틴에 대한 자세한 내용은 메시지 전달 함수를 참조하십시오.
단원
이 항목에는 다음과 같은 단원이 포함되어 있습니다.
소스 및 대상
메시지 전파
메시지 블록 형식 개요
unbounded_buffer 클래스
overwrite_buffer 클래스
single_assignment 클래스
call 클래스
transformer 클래스
choice 클래스
join 및 multitype_join 클래스
timer 클래스
메시지 필터링
메시지 예약
소스 및 대상
소스와 대상은 메시지 전달의 중요한 두 참가 요소입니다.소스는 메시지를 보내는 통신의 끝점을 나타내고대상은 메시지를 받는 통신의 끝점을 나타냅니다.소스는 메시지를 읽는 끝점으로 간주하고 대상은 메시지를 작성하는 끝점으로 간주할 수 있습니다.응용 프로그램에서는 소스와 대상을 함께 연결하여 메시징 네트워크를 구성합니다.
에이전트 라이브러리 두 추상 클래스를 사용 하 여 소스와 대상을 나타내는: concurrency::ISource 및 concurrency::ITarget.소스로 사용되는 메시지 블록 형식은 ISource에서 파생되고 대상으로 사용되는 메시지 블록 형식은 ITarget에서 파생됩니다.소스와 대상으로 사용되는 메시지 블록 형식은 ISource 및 ITarget에서 파생됩니다.
Top
메시지 전파
메시지 전파는 구성 요소 간에 메시지를 보내는 동작입니다.메시지 블록은 제공된 메시지를 수락하거나 거부하거나 연기할 수 있습니다.모든 메시지 블록 형식은 다양한 방식으로 메시지를 저장하고 전송합니다.예를 들어 unbounded_buffer 클래스는 개수에 관계없이 메시지를 저장하고 overwrite_buffer 클래스는 한 번에 하나의 메시지를 저장하며 변환기 클래스는 각 메시지의 변경된 버전을 저장합니다.이러한 메시지 블록 형식에 대해서는 이 문서의 뒷부분에서 자세히 설명합니다.
메시지 블록에서 메시지를 수락하면 선택적으로 작업을 수행할 수 있으며 메시지 블록이 소스인 경우 결과 메시지를 네트워크의 다른 멤버에게 전달합니다.메시지 블록은 필터 함수를 사용하여 받지 않을 메시지를 거부할 수 있습니다.필터에 대한 내용은 이 항목 뒷부분의 메시지 필터링 단원에서 자세히 설명합니다.메시지를 연기하는 메시지 블록은 해당 메시지를 예약한 후 나중에 사용할 수 있습니다.메시지 예약에 대한 내용은 이 항목 뒷부분의 메시지 예약 단원에서 자세히 설명합니다.
에이전트 라이브러리를 사용하면 메시지 블록이 메시지를 동기적 또는 비동기적으로 전달할 수 있습니다.예를 들어 send 함수를 사용하여 메시지를 동기적으로 메시지 블록에 전달하면 대상 블록이 메시지를 수락하거나 거부할 때까지 런타임에서 현재 컨텍스트를 차단합니다.예를 들어 asend 함수를 사용하여 메시지를 비동기적으로 메시지 블록에 전달하면 런타임에서 대상에 메시지를 제공하며 대상이 메시지를 수락할 경우 런타임에서 수신자에게 메시지를 전파하는 비동기 작업을 예약합니다.런타임에서는 간단한 작업을 사용하여 협조적 방식으로 메시지를 전파합니다.간단한 작업에 대한 자세한 내용은 작업 스케줄러(동시성 런타임)를 참조하십시오.
응용 프로그램에서는 소스와 대상을 함께 연결하여 메시징 네트워크를 구성합니다.일반적으로 네트워크를 연결하고 send 또는 asend를 호출하여 데이터를 네트워크에 전달합니다.원본 메시지 블록 대상에 연결 하려면 전화를 concurrency::ISource::link_target 메서드.원본 블록에서 대상의 연결을 끊으려면 호출을 concurrency::ISource::unlink_target 메서드.원본 블록의 모든 해당 대상에서 연결을 끊으려면 호출의 concurrency::ISource::unlink_targets 메서드가 있습니다.미리 정의된 메시지 블록 형식 중 하나가 범위를 벗어나거나 삭제되면 자동으로 모든 대상 블록과 연결이 끊어집니다.일부 메시지 블록 형식은 쓸 수 있는 최대 대상 개수를 제한합니다.다음 단원에서는 미리 정의된 메시지 블록 형식에 적용되는 제한 사항에 대해 설명합니다.
Top
메시지 블록 형식 개요
다음 표에서는 중요한 메시지 블록 형식의 역할에 대해 간략하게 설명합니다.
unbounded_buffer
메시지 큐를 저장합니다.overwrite_buffer
여러 번 읽고 쓸 수 있는 하나의 메시지를 저장합니다.single_assignment
한 번 쓸 수 있고 여러 번 읽을 수 있는 하나의 메시지를 저장합니다.call
메시지를 받으면 작업을 수행합니다.transformer
데이터를 받으면 작업을 수행하고 해당 작업의 결과를 다른 대상 블록에 보냅니다.transformer 클래스는 다른 입력 및 출력 형식에서 동작할 수 있습니다.choice
소스 집합에서 사용 가능한 첫 번째 메시지를 선택합니다.join 및 multitype join
소스 집합에서 모든 메시지를 받을 때까지 기다린 다음, 메시지를 다른 메시지 블록에 대한 하나의 메시지로 결합합니다.timer
메시지를 정기적으로 대상 블록에 보냅니다.
이러한 메시지 블록 형식에는 상황에 따라 유용하게 적용할 수 있는 다양한 특성이 있습니다.다음은 이러한 특성 중 일부입니다.
전파 형식: 메시지 블록을 데이터 소스로 사용할지, 데이터 수신자로 사용할지 아니면 둘 다로 사용할지를 지정합니다.
메시지 순서 지정: 메시지 블록에서 메시지를 보내고 받는 원래 순서를 그대로 유지할지 여부를 지정합니다.미리 정의된 각 메시지 블록 형식은 메시지를 보내고 받는 원래 순서를 유지합니다.
소스 개수: 메시지 블록에서 읽을 수 있는 최대 소스 개수입니다.
대상 개수: 메시지 블록에서 쓸 수 있는 최대 대상 개수입니다.
다음 표에서는 이러한 특성과 다양한 메시지 블록 형식의 관계를 보여 줍니다.
메시지 블록 형식 |
전파 형식(소스, 대상 또는 둘 다) |
메시지 순서 지정(순서 지정됨 또는 순서 지정 안 됨) |
소스 개수 |
대상 개수 |
---|---|---|---|---|
unbounded_buffer |
Both |
순서 지정됨 |
제한 없음 |
제한 없음 |
overwrite_buffer |
Both |
순서 지정됨 |
제한 없음 |
제한 없음 |
single_assignment |
Both |
순서 지정됨 |
제한 없음 |
제한 없음 |
call |
대상 |
순서 지정됨 |
제한 없음 |
적용할 수 없음 |
transformer |
Both |
순서 지정됨 |
제한 없음 |
1 |
choice |
Both |
순서 지정됨 |
10 |
1 |
join |
Both |
순서 지정됨 |
제한 없음 |
1 |
multitype_join |
Both |
순서 지정됨 |
10 |
1 |
timer |
소스 |
적용할 수 없음 |
적용할 수 없음 |
1 |
다음 단원에서는 메시지 블록 형식에 대해 자세히 설명합니다.
Top
unbounded_buffer 클래스
Concurrency::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;
}
이 예제의 결과는 다음과 같습니다.
33
44
55
unbounded_buffer 클래스를 사용하는 방법을 보여 주는 전체 예제를 보려면 방법: 다양한 공급자/소비자 패턴 구현을 참조하십시오.
Top
overwrite_buffer 클래스
Concurrency::overwrite_buffer 클래스와 유사한는 unbounded_buffer 제외 하 고는 클래스는 overwrite_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;
}
이 예제의 결과는 다음과 같습니다.
55
55
55
overwrite_buffer 클래스를 사용하는 방법을 보여 주는 전체 예제를 보려면 방법: 다양한 공급자/소비자 패턴 구현을 참조하십시오.
Top
single_assignment 클래스
Concurrency::single_assignment 클래스와 유사한는 overwrite_buffer 제외 하 고는 클래스는 single_assignment 개체는 한 번만 쓸 수 있습니다.overwrite_buffer 클래스와 마찬가지로 대상이 single_assignment 개체에서 메시지를 받으면 해당 메시지가 이 개체에서 제거되지 않습니다.따라서 여러 대상에 메시지의 복사본이 전달됩니다.single_assignment 클래스는 하나의 메시지를 여러 구성 요소에 브로드캐스팅하려는 경우에 유용합니다.
예제
다음 예제에서는 single_assignment 클래스를 사용하는 방법의 기본 구조를 보여 줍니다.이 예제에서는 세 개의 값을 single_assignment 개체에 보낸 다음 같은 개체에서 현재 값을 세 번 읽습니다.이 예제는 overwrite_buffer 클래스에 대한 예제와 비슷합니다.overwrite_buffer 및 single_assignment 클래스 둘 다 단일 메시지를 저장하지만 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;
}
이 예제의 결과는 다음과 같습니다.
33
33
33
single_assignment 클래스를 사용하는 방법을 보여 주는 전체 예제를 보려면 연습: 미래 구현을 참조하십시오.
Top
call 클래스
Concurrency::call 클래스 데이터를 받으면 작업 기능을 수행 하는 메시지 수신자 역할입니다.이 작업 함수는 람다 식, 함수 개체 또는 함수 포인터가 될 수 있습니다.call 개체는 메시지를 보내는 다른 구성 요소와 나란히 동작하므로 일반적인 함수 호출과는 동작 방식이 다릅니다.If a call 개체는 메시지를 받고 작업을 수행 중인 경우 해당 메시지를 큐에 추가합니다.모든 call 개체는 큐에 대기 중인 메시지를 받은 순서대로 처리합니다.
예제
다음 예제에서는 call 클래스를 사용하는 방법의 기본 구조를 보여 줍니다.이 예제에서는 받는 각각의 값을 콘솔에 출력하는 call 개체를 만듭니다.그런 다음 call 개체에 세 개의 값을 보냅니다.call 개체는 별도의 스레드에서 메시지를 처리하므로 이 예제에서는 카운터 변수와 event 개체를 사용하여 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();
}
이 예제의 결과는 다음과 같습니다.
33
44
55
call 클래스를 사용하는 방법을 보여 주는 전체 예제를 보려면 방법: call 및 transformer 클래스에 작업 함수 제공을 참조하십시오.
Top
transformer 클래스
Concurrency::transformer 메시지 보낸 사람 및 메시지 수신기 클래스 동작 합니다.transformer 클래스는 데이터를 받으면 사용자 정의 작업 함수를 수행하므로 call 클래스와 비슷합니다.그러나 transformer 클래스는 작업 함수의 결과도 수신자 개체에 보냅니다.call 개체와 마찬가지로 transformer 개체는 메시지를 보내는 다른 구성 요소와 나란히 동작합니다.transformer 개체는 메시지를 받고 작업을 수행 중인 경우 해당 메시지를 큐에 추가합니다.모든 transformer 개체는 큐에 대기 중인 메시지를 받은 순서대로 처리합니다.
transformer 클래스는 메시지를 하나의 대상에 보냅니다.설정한 경우는 _PTarget 생성자에 매개 변수로 NULL를 호출 하 여 나중에 대상을 지정할 수 있습니다는 concurrency::link_target 메서드.
에이전트 라이브러리에서 제공하는 다른 모든 비동기 메시지 블록 형식과 달리 transformer 클래스는 다른 입력 및 출력 형식에서 동작할 수 있습니다.한 형식에서 다른 형식으로 데이터를 전송할 수 있는 기능으로 인해 transformer 클래스는 많은 동시 네트워크에서 핵심 구성 요소로 사용됩니다.또한 transformer 개체의 작업 함수에서 더 세분화된 병렬 기능을 추가할 수 있습니다.
예제
다음 예제에서는 transformer 클래스를 사용하는 방법의 기본 구조를 보여 줍니다.이 예제에서는 double 값을 출력으로 생성하기 위해 각 입력 int 값에 0.33을 곱하는 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.89
14.52
18.15
transformer 클래스를 사용하는 방법을 보여 주는 전체 예제를 보려면 방법: 데이터 파이프라인에서 transformer 사용을 참조하십시오.
Top
choice 클래스
Concurrency::choice 클래스 소스 집합에서 사용 가능한 첫 번째 메시지를 선택 합니다.choice 클래스는 데이터 흐름 메커니즘 대신 제어 흐름 메커니즘을 나타냅니다. 비동기 에이전트 라이브러리 항목에서는 데이터 흐름과 제어 흐름의 차이점에 대해 설명합니다.
choice 개체를 읽는 것은 bWaitAll 매개 변수가 FALSE로 설정된 Windows API WaitForMultipleObjects 함수를 호출하는 것과 비슷합니다.그러나 choice 클래스는 외부 동기화 개체 대신 이벤트 자체에 데이터를 바인딩합니다.
일반적으로 사용 하는 choice 함께 클래스는 concurrency::receive 함수를 응용 프로그램의 제어 흐름을 드라이브에.다양한 형식을 포함하는 메시지 버퍼에서 선택해야 하는 경우 choice 클래스를 사용하고,같은 형식을 포함하는 메시지 버퍼에서 선택해야 할 경우에는 single_assignment 클래스를 사용합니다.
소스를 choice 개체에 연결하는 순서는 선택되는 메시지를 결정할 수 있으므로 중요합니다.예를 들어 메시지가 이미 포함되어 있는 여러 메시지 버퍼를 choice 개체에 연결하는 경우를 가정해 보십시오.choice 개체는 첫 번째로 연결되는 소스에서 메시지를 선택합니다.모든 소스를 연결하고 나면 choice 개체는 각 소스에 메시지가 전달되는 순서를 유지합니다.
예제
다음 예제에서는 choice 클래스를 사용하는 방법의 기본 구조를 보여 줍니다.예제는 concurrency::make_choice 함수를 만들 수는 choice 세 메시지 블록 중에서 선택 하는 개체입니다.그런 다음 다양한 피보나치 수(Fibonacci number)를 계산하고 각 결과를 다른 메시지 블록에 저장합니다.그리고 나서 처음에 완료한 작업을 기반으로 하는 메시지를 콘솔에 출력합니다.
// 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
35th 피보나치 수(Fibonacci number)를 계산하는 작업이 처음에 완료된다는 보장이 없으므로 이 예제의 출력은 달라질 수 있습니다.
이 예제는 concurrency::parallel_invoke 병렬로 피보나치 숫자를 계산 하는 알고리즘입니다.parallel_invoke에 대한 자세한 내용은 병렬 알고리즘을 참조하십시오.
choice 클래스를 사용하는 방법을 보여 주는 전체 예제를 보려면 방법: 완료된 작업 간 선택을 참조하십시오.
Top
join 및 multitype_join 클래스
Concurrency::join 및 concurrency::multitype_join 클래스를 사용 하면 메시지가 각 멤버 집합의 소스에 대 한 기다려야 합니다.join 클래스는 공통 메시지 형식을 포함하는 소스 개체에서 동작하고,multitype_join 클래스는 서로 다른 메시지 형식을 포함할 수 있는 소스 개체에서 동작합니다.
join 또는 multitype_join 개체를 읽는 것은 bWaitAll 매개 변수가 TRUE로 설정된 Windows API WaitForMultipleObjects 함수를 호출하는 것과 비슷합니다.그러나 choice 개체와 마찬가지로 join 및 multitype_join 개체도 외부 동기화 개체 대신 이벤트 자체에 데이터를 바인딩하는 이벤트 메커니즘을 사용합니다.
join 개체를 읽으면 std::vector 개체가 생성되고multitype_join 개체를 읽으면 std::tuple 개체가 생성됩니다.이러한 개체에서 해당하는 소스 버퍼와 같은 순서로 나타나는 요소는 join 또는 multitype_join 개체에 연결됩니다.소스 버퍼를 join 또는 multitype_join 개체에 연결하는 순서가 결과 vector 또는 tuple 개체에서의 요소 순서와 관련되므로 조인에서 기존 소스 버퍼의 연결을 끊지 않는 것이 좋습니다.이 연결을 끊으면 지정되지 않은 동작이 발생할 수 있습니다.
Greedy 조인 및 Non-Greedy 조인
join 및 multitype_join 클래스는 greedy 조인 및 non-greedy 조인 개념을 지원합니다.greedy 조인은 메시지를 사용할 수 있게 되면 모든 메시지를 사용할 수 있을 때까지 각 소스로부터 메시지를 수락합니다.non-greedy 조인은 두 단계로 메시지를 받습니다.먼저 non-greedy 조인은 각 소스의 메시지가 제공될 때까지 기다립니다.두 번째로 모든 소스 메시지를 사용할 수 있게 되면 각 메시지를 예약하려고 시도합니다.non-greedy 조인이 각 메시지를 예약할 수 있는 경우 모든 메시지를 사용하고 대상에 전파합니다.그렇지 않으면 메시지 예약을 해제하거나 취소하고 각 소스가 메시지를 받을 때까지 다시 기다립니다.
Greedy 조인은 메시지를 즉시 수락하므로 non-greedy 조인보다 효율적입니다.그러나 드문 경우이긴 하지만 greedy 조인을 사용하면 교착 상태가 발생할 수 있습니다.공유 소스 개체를 하나 이상 포함하는 조인이 여러 개 있는 경우 non-greedy 조인을 사용하십시오.
예제
다음 예제에서는 join 클래스를 사용하는 방법의 기본 구조를 보여 줍니다.이 예제는 concurrency::make_join 함수를 만들 수는 join 3에서 수신 하는 개체 single_assignment 개체.이 예제에서는 다양한 피보나치 수(Fibonacci number)를 계산하고 각 결과를 다른 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 = 9227465
fib37 = 24157817
half_of_fib42 = 1.33957e+008
이 예제는 concurrency::parallel_invoke 병렬로 피보나치 숫자를 계산 하는 알고리즘입니다.parallel_invoke에 대한 자세한 내용은 병렬 알고리즘을 참조하십시오.
join 클래스를 사용하는 방법을 보여 주는 전체 예제를 보려면 방법: 완료된 작업 간 선택 및 연습: join을 사용하여 교착 상태 방지를 참조하십시오.
Top
timer 클래스
Concurrency::timer 메시지 원본 클래스 역할.timer 개체는 지정된 시간이 경과하면 대상에 메시지를 보냅니다.timer 클래스는 메시지 보내기를 연기해야 하거나 정기적으로 메시지를 보내려는 경우에 유용합니다.
timer 클래스는 메시지를 하나의 대상에 보냅니다.설정한 경우는 _PTarget 생성자에 매개 변수로 NULL를 호출 하 여 나중에 대상을 지정할 수 있습니다는 concurrency::ISource::link_target 메서드.
timer 개체는 반복되거나 반복되지 않을 수 있습니다.반복되는 타이머를 만들려면 생성자를 호출할 때 _Repeating 매개 변수에 true를 전달합니다.그렇지 않으면 _Repeating 매개 변수에 false를 전달하여 반복되지 않는 타이머를 만듭니다.반복되는 타이머는 각 간격마다 같은 메시지를 대상에 보냅니다.
에이전트 라이브러리는 시작되지 않은 상태로 timer 개체를 만듭니다.타이머 개체를 시작 하는 호출을 concurrency::timer::start 메서드.중지 하는 timer 개체, 개체 또는 호출 파괴를 concurrency::timer::stop 메서드.반복 하는 타이머를 일시 중지 하려면 호출 하는 concurrency::timer::pause 메서드.
예제
다음 예제에서는 timer 클래스를 사용하는 방법의 기본 구조를 보여 줍니다.그리고 timer 및 call 개체를 사용하여 시간이 많이 걸리는 작업의 진행률을 보고합니다.
// 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 클래스를 사용하는 방법을 보여 주는 전체 예제를 보려면 방법: 정기적으로 메시지 보내기를 참조하십시오.
Top
메시지 필터링
메시지 블록 개체를 만들 때 메시지 블록이 메시지를 수락할지 거부할지를 결정하는 필터 함수를 제공할 수 있습니다.필터 함수는 메시지 블록이 특정 값만 받을 수 있게 하는 유용한 방법입니다.
다음 예제에서는 필터 함수를 사용하여 짝수만 수락하는 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 (_Type)
bool (_Type const &)
불필요하게 데이터를 복사하는 일이 없도록 하려면 값으로 전파되는 집계 형식인 경우 두 번째 형식을 사용합니다.
메시징 필터링은 구성 요소가 데이터를 받을 때 계산을 수행하는 데이터 흐름 프로그래밍 모델을 지원합니다.메시지 전달 네트워크에서 데이터 흐름을 제어하는 데 필터 함수를 사용하는 예제를 보려면 방법: 메시지 블록 필터 사용, 연습: 사용자 지정 데이터 흐름 에이전트 만들기 및 연습: 이미지 처리 네트워크 만들기를 참조하십시오.
Top
메시지 예약
메시지 예약을 사용하면 메시지 블록이 나중에 메시지를 사용하도록 예약할 수 있습니다.일반적으로 메시지 예약이 직접 사용되지는 않습니다.그러나 메시지 예약을 이해하면 미리 정의된 메시지 블록 형식의 일부 동작을 이해하는 데 도움이 됩니다.
greedy 조인 및 non-greedy 조인을 살펴봅니다.둘 다 메시지 예약을 사용하여 나중에 메시지를 사용하도록 예약합니다.앞에서 설명한 non-greedy 조인은 두 단계로 메시지를 받습니다.첫 번째 단계에서는 non-greedy join 개체에서 각 소스가 메시지를 받을 때까지 기다립니다.그런 다음 각 메시지를 예약하려고 시도합니다.non-greedy 조인이 각 메시지를 예약할 수 있는 경우 모든 메시지를 사용하고 대상에 전파합니다.그렇지 않으면 메시지 예약을 해제하거나 취소하고 각 소스가 메시지를 받을 때까지 다시 기다립니다.
여러 소스에서 입력 메시지를 읽는 greedy 조인은 각 소스에서 메시지를 받기 위해 기다리는 동안 메시지 예약을 사용하여 추가 메시지를 읽습니다.예를 들어 A 및 B 메시지 블록에서 메시지를 받는 greedy 조인을 가정해 봅니다.greedy 조인이 B에서 두 개의 메시지를 받지만 A에서는 메시지를 받지 않은 경우 greedy 조인은 B의 두 번째 메시지에 대한 고유 메시지 식별자를 저장합니다.greedy 조인은 A에서 메시지를 받고 전파한 후 저장된 메시지 식별자를 사용하여 B의 두 번째 메시지를 계속해서 사용할 수 있는지 확인합니다.
고유 사용자 지정 메시지 블록 형식을 구현할 때 메시지 예약을 사용할 수 있습니다.사용자 지정 메시지 블록 형식을 만드는 방법에 대한 예제를 보려면 연습: 사용자 지정 메시지 블록 만들기를 참조하십시오.
Top