Asynchronous Agents Library – message block 3. ( overwrite_buffer & single_assignment )
VC++ 10 Concurrency Runtime 2010. 7. 27. 18:00Asynchronous Agents Library
– message block 3. ( overwrite_buffer & single_assignment )
작성자: 임준환( mumbi at daum dot net )
시작하는 글
지난 글 unbounded_buffer 에 이어 또 다른 message block 인 overwrite_buffer 와 single_assignment 에 대해서 알아보도록 하겠습니다.
Message block 들은 특징들이 모두 다르기 때문에 지난 unbounded_buffer 을 생각하시면 이해가 어려울 수 있습니다. message block 하나 하나의 쓰임새가 다르므로 새로운 것을 알아본다고 생각하시는 것이 좋을 것 같습니다.
overwrite_buffer< _Type >
지금부터 설명드릴 overwrite_buffer 은 unbounded_buffer 와는 달리 하나의 변수라고 생각하시면 이해하기 쉬울 것입니다.
Concurrency runtime 을 사용하지 않고, 스레드 간의 상태나 정보를 공유하려면 전역 변수나 힙( heap ) 에 할당된 변수에 락( lock ) 을 걸어 사용해야 합니다.
overwrite_buffer 는 방금 언급한 번거로운 작업들을 알아서 해줍니다. 내부에서 힙에 메모리를 할당하고, 접근 시 락을 겁니다. 하지만 사용하는 우리는 그런 것들을 신경 쓰지 않고 마치 지역 변수처럼 사용할 수 있습니다.
unbounded_buffer 는 외부에서 message 를 받아가면 내부에서 해당 message 가 제거되는 반면에, overwrite_buffer 는 제거되지 않습니다. 또한 하나의 변수와도 같기 때문에 외부에서 message 를 보내면 이 전의 message 를 덮어쓰고 새 message 가 저장됩니다.
결국 overwrite_buffer 는 단 하나의 message 만을 갖게 됩니다.
그럼 overwrite_buffer 의 멤버 함수에 대해서 알아보도록 하겠습니다.
멤버 함수
생성자와 소멸자를 제외한 public 인 멤버 함수들입니다.
bool has_value() const
현재 message 를 가지고 있는지 반환합니다.
어떠한 message 도 갖지 않을 경우에 false 를 반환합니다. 만약, 한번이라도 overwrite_buffer 에 message 가 전달된다면 그 후부터는 true 를 반환합니다. overwrite_buffer 는 외부에서 message 를 받아가도 내부의 message 가 제거되지 않기 때문입니다.
Message 를 갖고 있지 않을 때, 외부에서 동기 함수인 receive() 를 사용해 message 를 얻기를 원한다면 overwrite_buffer 에 message 가 들어올 때까지 기다립니다. message 가 제거되지 않기 때문에 한번이라도 overwrite_buffer 가 message 를 받으면 receive() 가 기다리는 일은 없을 것입니다.
_Type value();
현재 가지고 있는지 message 를 반환합니다.
내부적으로 동기 전달 함수인 receive() 를 사용하므로 message 를 가지고 있지 않다면 message 를 갖게 될 때까지 기다립니다. 만약 이 때, has_value() 를 호출했다면 false 를 반환할 것입니다.
Message 가 제거되지 않기 때문에 전달 함수를 이용해 message 를 받아갈 경우, 복사본이 전달됩니다.
예제
overwrite_buffer 의 간단한 예제를 구현해보도록 하겠습니다.
시나리오
네트워크 지연 시간을 갱신하고, 출력하는 프로그램을 작성할 것입니다.
네트워크 지연 시간을 갱신하는 역할을 하는 agent 와 갱신된 정보를 출력하는 agent 가 하나의 overwrite_buffer 를 공유하여 사용하는 예제입니다.
코드
#include <iostream> #include <array> #include <agents.h> using namespace std; using namespace Concurrency; // 지연 시간을 얻어오는 agent. class PingUpdater : public agent { public: PingUpdater( const array< unsigned int, 5 >& delayTimeSource, ITarget< unsigned int >& targetBlock ) : delayTimeSource( delayTimeSource ) , targetBlock( targetBlock ) { } protected: // 2초마다 지연 시간을 얻어 옴. void run() { while( true ) { asend( this->targetBlock, this->GetDelayTime() ); Concurrency::wait( 2000 ); } this->done(); } // 지연 시간을 시뮬레이션하는 함수. unsigned int GetDelayTime() { static unsigned int index = 0; unsigned int delayTime = this->delayTimeSource[ index ]; if( index + 1 < this->delayTimeSource.size() ) ++index; else index = 0; return delayTime; } private: const array< unsigned int, 5 >& delayTimeSource; ITarget< unsigned int >& targetBlock; }; // 지연 시간을 출력하는 agent. class PingDisplayer : public agent { public: PingDisplayer( ISource< unsigned int >& sourceBlock ) : sourceBlock( sourceBlock ) { } protected: // 1초마다 지연 시간을 출력한다. void run() { while( true ) { this->Display( receive( this->sourceBlock ) ); Concurrency::wait( 1000 ); } this->done(); } // 지연 시간을 출력하는 함수. void Display( unsigned int delayTime ) { wcout << L"current delay time: " << delayTime << endl; } private: ISource< unsigned int >& sourceBlock; }; int main() { // 네트워크 지연 시간의 시뮬레이션 정보. array< unsigned int, 5 > delayTimeSource = { 210, 211, 261, 246, 223 }; // 공유 버퍼 overwrite_buffer< unsigned int > delayTimeBuffer; // 네트워크 지연 시간을 갱신하는 agent 와 출력하는 agent. PingUpdater updater( delayTimeSource, delayTimeBuffer ); PingDisplayer displayer( delayTimeBuffer ); // agent 시작. updater.start(); displayer.start(); // agent 의 작업이 모두 끝날 때까지 대기. agent* waitingAgents[2] = { &updater, &displayer }; agent::wait_for_all( 2, waitingAgents ); }
[ 코드1. overwrite_buffer 를 이용한 네트워크 지연 시간 갱신 및 출력 예제 ]
PingUpdater 클래스는 agent 클래스로 네트워크 지연 시간을 갱신하는 역할을 합니다. 2초에 한 번씩 시뮬레이션을 위해 준비된 정보를 순회하며 얻어와서 overwrite_buffer 에 전달합니다.
PingDisplayer 클래스도 agent 클래스로 갱신된 네트워크 지연 시간을 화면에 출력하는 역할을 합니다. 1초에 한번씩 overwrite_buffer 로부터 갱신된 정보를 가져와서 화면에 출력합니다.
예제에서 사용된 Concurrency::wait() 는 Win32 API 의 Sleep() 과 같은 역할을 합니다. agent::wait() 과 혼동하지 않길 바랍니다.
위 코드를 보시면 굉장히 직관적이고, 간단하게 멀티 스레드 프로그래밍을 할 수 있다는 것을 알 수 있을 것입니다.
[ 그림1. overwrite_buffer 를 이용한 네트워크 지연 시간 갱신 및 출력 예제 ]
single_assignment< _Type >
single_assignment 는 위에서 설명한 overwrite_buffer 와 거의 흡사합니다.
단지 다른 점이 있다면 message 를 한번만 받을 수 있다는 것입니다. 만약 두 번 이상 보낸 다면 두 번째부터는 무시됩니다.
멤버 함수 또한 거의 같지만, 다른 점을 알아보겠습니다.
멤버 함수
생성자와 소멸자를 제외한 public 인 함수들입니다.
bool has_value() const
위에서 설명한 overwrite_buffer 의 has_value() 와 같습니다.
Message 를 단 한번도 받지 않았다면 false 를 반환하고, 받았다면 true 를 반환합니다.
_Type const & value()
overwrite_buffer 의 value() 와 같은 기능을 합니다.
하지만 값을 반환하지 않고 const 참조를 반환한다는 것이 다릅니다.
overwrite_buffer 의 value() 와 마찬가지로 message 를 갖고 있지 않다면 message 를 갖게 될 때까지 기다립니다.
마치는 글
이번 글에서는 overwrite_buffer 와 single_assignment 에 대해서 알아보았습니다.
single_assignment 는 overwrite_buffer 와 거의 흡사하기 때문에 예제는 생략하였습니다.
지난 글에서 본 unbounded_buffer 와는 분명히 쓰임새가 다르므로 특징을 잘 파악해두시면 좋을 것입니다.
다음 글에서 또 다른 message block 을 소개해드릴 것입니다. 그 message block 또한 쓰임새가 분명히 다르므로 Asynchronous Agents Library 의 활용도가 굉장히 넓다는 것을 아시게 될 것입니다.
'VC++ 10 Concurrency Runtime' 카테고리의 다른 글
Asynchronous Agents Library – message block 5. ( transformer ) (0) | 2010.08.03 |
---|---|
Asynchronous Agents Library – message block 4. ( call ) (0) | 2010.07.31 |
Asynchronous Agents Library – message block 2. ( unbounded_buffer ) (2) | 2010.07.18 |
Asynchronous Agents Library – message block 1. ( 인터페이스 ) (0) | 2010.07.10 |
Asynchronous Agents Library – message 전달 함수. 2 ( 수신 ) (0) | 2010.07.03 |