Asynchronous Agents Library

– message block 1. ( 인터페이스 )

작성자: 임준환( mumbi at daum dot net )

 

시작하는 글

 이전 글까지 Asynchronous Agents Library( 이하, AAL ) 의 일부인 agent 와 message 전달 함수에 대해 알아보았습니다. agent 만 알아도 어느 정도 비 동기 처리를 쉽게 구현할 수 있습니다.

 이번 글에서는 agent 간 소통을 할 수 있는 message block 들에 대해서 알아보겠습니다. message block 을 이용하면 agent 간 데이터 또는 상태 동기화를 할 수 있습니다.

 AAL 은 스레드로부터 안전한 방식으로 구현되었고, 추상화되었습니다. 그래서 agent 객체와 message block 을 이용한 동기화 로직이 직관적이고 쉽게 흐름을 파악할 수 있어 데드락( dead-lock ) 을 방지하기 용이합니다.

 그럼 지금부터 agent 를 이용한 비 동기 처리에 날개를 달아주는 message block 에 대해 알아보도록 하겠습니다.

 

Message 객체

 예전 글부터 message, message 메커니즘, message 전달 함수, message block 등을 언급하면서 항상 message 란 개념을 사용했습니다.

 이 개념은 실제 클래스로 존재합니다. 하지만 단지 message 를 래핑( wrapping ) 할 뿐, 전혀 다른 기능을 가지고 있지 않은 클래스입니다.

 한 가지 기능이 있다면 식별자( id )를 갖는다는 것입니다. message 클래스는 Concurrency Runtime 의 _Runtime_object 클래스를 상속 받습니다. 이 클래스는 Runtime 에 의해 생성될 때 자동으로 id 를 갖게 됩니다. 이 id 를 알아보는 함수는 msg_id() 입니다. 이 메서드의 접근자가 public 으로 되어 있어 message 클래스에서도 사용 가능합니다.

 이 msg_id() 가 반환한 값은 message block 에서 사용되는 runtime_object_identity 형입니다. 몇몇 message block 메서드의 runtime_object_identity 형의 매개변수에 인자로 사용할 수 있습니다.

 사실, 직접 message block 을 구현하지 않는 한, message 클래스는 직접 사용할 경우는 없을 것입니다. 우리는 보내고 받는 데이터를 공급하면 내부적으로 그 데이터를 message 클래스로 래핑하고 message block 내부에서 사용하게 되는 것입니다. 그러므로 크게 신경쓰지 않아도 됩니다.

 

Source 와 target

 Message block 은 크게 두 가지 종류로 나눌 수 있습니다. 하나는 source 이고 다른 하나는 target 입니다.

 Message block 에서의 source 는 message 를 보낼 message block 을 일컫습니다. 마찬가지로 target 은 message 를 받을 message block 을 뜻합니다.

ISource 인터페이스

 Source 는 AAL 의 하나의 개념이지만, 이것을 인터페이스로 추상화 하였습니다. 이것이 ISource 인터페이스입니다.

 그러므로 source 로 쓰일 message block 들은 ISource 인터페이스를 상속하여 구현되었습니다. 만약 직접 source 로 사용될 message block 을 구현하신다면 ISource 인터페이스를 상속해야 합니다.

- ISource 인터페이스의 선언

template<   class _Type>class ISource;

[ 코드1. ISource 인터페이스의 선언 ]

 템플릿 매개변수인 _Type 은 message 로 쓰일 데이터 형( type )입니다. _Type 은 public typedef 인 source_type 으로 사용할 수 있습니다.

 

- ISource 인터페이스의 메서드

virtual void link_target(ITarget<_Type> * _PTarget) = 0;

[ 코드2. ISource::link_target() ]

 link_target() 은 target 인 message block 과 연결합니다. 여기서 연결의 의미는 자동으로 전달된다는 의미로 생각하시면 되겠습니다.

 즉, 이 ISource 를 상속받은 message block 에 link_target() 으로 target message block 을 연결했을 경우, 이 message block 의 message 들은 직접 전달 함수를 사용하지 않아도 자동으로 target message block 으로 전달됩니다.

 연결할 target 은 여러 개일 수 있습니다. 그러나 ISource 를 상속한 message block 의 구현에 따라 첫 번째 target 만 동작할 수도 있습니다. 예로 unbounded_buffer 가 있습니다. unbounded_buffer 는 내부적으로 큐를 구현하고 있어 전달 후, message 가 큐에서 제거되므로 두 번째 연결된 target 이 있더라도 message 를 보낼 수 없습니다.

 매개변수인 _PTarget 은 연결할 target message block 입니다. _PTarget 의 데이터 형인 ITarget 은 target 을 추상화한 인터페이스입니다. 곧 설명하도록 하겠습니다.

 _PTarget 이 NULL 이라면 invalid_argument 예외가 발생합니다.

 

virtual void unlink_target(ITarget<_Type> * _PTarget) = 0;

[ 코드3. ISource::unlink_target() ]

 unlink_target() 은 link_target() 으로 연결된 target 들 중 매개변수인 _PTarget 에 지정된 target 의 연결을 해제합니다.

 _PTarget 이 NULL 이라면 invalid_argument  예외가 발생합니다. 또한 _PTarget 이 연결된 target 들 중에 없다면 아무 것도 하지 않습니다.

 

virtual void unlink_targets() = 0;

[ 코드4. ISource::unlink_targets() ]

 unlink_targets() 는 연결된 모든 target 들의 연결을 해제합니다.

 

virtual message<_Type> * accept(runtime_object_identity _MsgId, ITarget<_Type> * _PTarget) = 0;

[ 코드5. ISource::accept() ]

 accept() 는 target 에서 호출되지만, source 가 제공합니다. source 의 message 를 수락하고, 소유권이 이전됩니다.

 매개변수인 runtime_object_identity 는 message 객체의 msg_id() 로 얻을 수 있습니다. 실제로 runtime_object_identity __int32 를 typedef 한 것이고, Concurrency Runtime 에서 객체를 생성할 때 지정되는 고유의 번호입니다.

 다른 매개변수인 _PTarget 은 message 를 수락하는 target 입니다.

 수락된 message 가 반환됩니다.

 

virtual bool reserve(runtime_object_identity _MsgId, ITarget<_Type> * _PTarget) = 0;

[ 코드6. ISource::reserve() ]

 reserve() 는 message 를 예약합니다. 예약을 성공한 message 는 message 를 얻기 위한 comsume() 이나 예약을 해제 위한 release() 를 호출해야 합니다.

 매개변수는 위의 accept() 와 같습니다.

 예약에 성공한 경우 true 를, 실패한 경우 false 를 반환합니다. 실패할 수 있는 이유는 다양합니다. 이미 예약되었거나, 구현한 message block 의 특징에 따라 예약에 실패할 수 있습니다.

 

virtual message<_Type> * consume(runtime_object_identity _MsgId, ITarget<_Type> * _PTarget) = 0;

[ 코드7. ISource::consume() ]

 consume() 은 위의 accept() 와 비슷합니다.

 다른 점이 있다면 reserve() 를 호출해 true 를 반환했을 때에만 consume() 을 호출해야 합니다. 보통 reserve() 를 호출하지 않았거나 _Ptarget 이 예약된 target 과 다를 경우 bad_target 예외가 발생합니다.

 매개변수는 위의 accept() 와 같습니다.

 

virtual void release(runtime_object_identity _MsgId, ITarget<_Type> * _PTarget) = 0;

[ 코드8. ISource::release() ]

 release() 는 예약된 것을 해제합니다.

 매개변수는 accept() 와 같습니다.

 

virtual void acquire_ref(ITarget<_Type> * _PTarget) = 0;

[ 코드9. ISource::acquire_ref() ]

 acquire_ref() 는 참조 개수를 증가시킵니다. 현재 link_target() 으로 연결된 target 에서 호출됩니다.

 매개변수인 _PTarget 은 link_target() 으로 연결된 target 입니다.

 

virtual void release_ref(ITarget<_Type> * _PTarget) = 0;

[ 코드10. ISource::release_ref() ]

 release_ref() 는 참조 개수를 감소시킵니다. 현재 link_target() 으로 연결된 target 에서 호출됩니다.

매개변수인 _PTarget 은 link_target() 으로 연결된 target 입니다.

 

ITarget 인터페이스

 Target 또한 source 와 마찬가지로 AAL 의 하나의 개념이지만, 이것을 추상화 하였습니다. 이것이 ITarget 인터페이스 입니다.

 Target 으로 사용할 message block 을 구현하신다면 ITarget 인터페이스를 상속해야 합니다.

- ITarget 인터페이스의 선언

template<   class _Type>class ITarget;

[ 코드11. ITarget 인터페이스의 선언 ]

 템플릿 매개변수인 _Type 은 message 로 사용될 데이터 형입니다. _Type 은 public typedef 인 type 으로 사용할 수 있습니다.

 Target 은 필터를 지정할 수 있습니다. 그래서 필터 함수의 시그니처( signature )인 bool ( _Type const & ) 를 typedef std::tr1::function<bool(_Type const&)> filter_method 로 정의되어 있습니다.

- ITarget 인터페이스의 메서드

virtual message_status propagate(message<_Type> * _PMessage, ISource<_Type> * _PSource) = 0;

[ 코드12. ITarget::propagate() ]

 propagate() 는 지정된 source 로부터 해당 message 를 비 동기 방식으로 가져옵니다.

 매개변수인 _PMessage 는 가져올 message 이고, _PSource 는 보내는 message block 입니다. _PMessage 나 _PSource 가 NULL 일 경우, invalid_argument 예외를 발생할 수 있습니다.

 Message 의 전달이 성공 또는 실패 등의 message 상태를 반환합니다.

 

virtual message_status send(message<_Type> * _PMessage, ISource<_Type> * _PSource) = 0;

[ 코드13. ITarget::send() ]

 send() 는 지정된 source 로부터 해당 message 를 동기 방식으로 가져옵니다.

 매개변수는 propagate() 와 같고, 예외 또한 같습니다.

 Message의 생성 이외에 네트워크와 함께 사용할 경우, 데드락( dead lock ) 을 초래할 수 있습니다.

 

virtual void link_source(ISource<_Source_type> * _PSource)

[ 코드14. ITarget::link_source() ]

 link_source() 는 source 의 link_target() 에 대응되는 함수로 지정된 source 를 연결합니다.

 하지만, 이 함수는 target 에서 호출하면 안되고, source 에서 link_target() 와 함께 호출하여 서로 연결되어야 합니다.

 

virtual void unlink_source(ISource<_Source_type> * _PSource)

[ 코드15. ITarget::unlink_target() ]

 unlink_source() 는 unlink_target() 에 대응되는 함수로 지정된 source 와의 연결을 해제합니다.

 하지만, link_source() 와 마찬가지로 target 에서 호출하면 안되고, source 에서 unlink_target()나 unlink_targets() 와 함께 호출하여 서로 연결을 해제해야 합니다.

 

virtual void unlink_sources()

[ 코드16. ITarget::unlink_sources() ]

 unlink_sources() 는 unlink_targets() 에 대응되는 함수로 지정된 source 들과의 연결을 모두 해제합니다.

 

마치는 글

 이번 글에서는 message block 구현 시, 상속해야 할 인터페이스인 ISourceITarget 에 대해서 알아보았습니다.

 실제로 ISourceITarget 의 메서드들을 직접 호출하는 경우는 거의 없으며, message block 내부에서 사용됩니다.

 Message 를 전달하기 위해서는 위 인터페이스들의 메서드들보다 message 전달 함수들을 많이 사용합니다.

 이번에 소개한 인터페이스들의 구현 클래스들에 대해 아직 소개하지 않았고, 이 인터페이스들의 메서드들이 내부적으로 사용되지만 사용자가 직접 호출할 경우가 드물기 때문에 예제를 작성하지 않았습니다.

 다음 글에서 위 인터페이스들을 구현한 구현 클래스들에 대해서 살펴보고 예제를 보도록 하겠습니다.

[Step. 05] 관리 코드의 array를 비관리 코드에 포인터로 전달

C++/CLI 2010. 7. 9. 08:30 Posted by 알 수 없는 사용자

아마 C++ 프로그래머가 C++/CLI를 사용할 때 가장 신경 쓰이는 부분이 관리 코드를 어떻게 하면 비관리 코드와 연동하는 방법이라고 생각합니다.

 

그래서 아직 C++/CLI의 델리게이트 등 C++/CLI의 특징을 설명하지 않은 것이 많지만 이런 것은 C#를 공부하면 배울 수 있는 것이므로 급하지 않다고 생각합니다. 그래서 관리 코드와 비 관리 코드의 연동에 대해서 앞으로 몇 차례에 걸쳐서 설명하려고 합니다.

 

이번은 첫 번째로 간단하게 array로 만든 배열을 비관리 코드의 포인터로 어떻게 전달하는지 설명하겠습니다.

 

먼저 코드를 봐 주세요^^

#include <Iostream>

 

using namespace System;

 

void DumpNativeArray( int* pArrNums, int length )

{

    for( int i=0; i<length; i++ )

    {

        std::cout << pArrNums[i] << std::endl;

    }

}

 

int main()

{

array< int >^ ArrNums = gcnew array<int>(3);

ArrNums[0] = 1;

ArrNums[1] = 2;

ArrNums[2] = 3;

 

     pin_ptr<int> pNative = &ArrNums[0];

     DumpNativeArray(pNative,ArrNums->Length);

     pNative = nullptr;

 

getchar();

     return 0;

}

 

위 코드의 핵심은

pin_ptr<int> pNative = &ArrNums[0];

입니다.

 

앞서 설명한 pin_ptr을 사용하였습니다. pin_ptr을 사용하여 관리 힙에 할당된 객체가 이동하지 못하도록 고정합니다. 고정하는 이유는 비관리 코드로 메모리 주소를 넘기기 때문에 관리 힙에서 이동이 되면 안되기 때문입니다.


또 여기서 자세히 봐야 되는 것이 있습니다.

pin_ptr<int> pNative = &ArrNums[0];


pNative&ArrNums이 아닌 &ArrNums[0]을 대입하였습니다. 이유는 관리 코드에서는 &ArrNums ArrNums의 요소가 아닌 ArrNums 오브젝트 자체를 가리키는 것이기 때문입니다.

&ArrNums[0]을 대입해야 ArrNums에 들어가 있는 요소의 첫 번째 주소를 비관리 코드에 주소를 넘길 수 있습니다.

 



제가 요즘 바빠서 이번은 아주 간단하게 이것으로 끝내겠습니다.^^;

다음에는 문자열 변환에 대해서 설명하겠습니다.

 

 

참조

http://mag.autumn.org/Content.modf?id=20050507224044

 

 

ASP.NET 의 WebMatrix & Razor 신 기술 소개

------------- 2010. 7. 7. 17:09 Posted by POWERUMC

오늘 Microsoft 의 Scottgu's Blog 를 통해 WebMatrix & Razor 기술이 소개되었습니다.    

우선 간단하게 용어를 정리해봅시다.

WebMatrix

경량화한 웹 개발 도구

Razor

ASP.NET 의 뷰(View) 엔진

즉, WebMatrix&Razor 는 빠르게 웹 개발 환경을 구성하고 Razor 의 뷰(View) 엔진을 이용하여 신속하게 웹 페이지를 개발하고자 합니다. 웹 환경/웹 개발/데이터베이스/웹 개발 도구 등 WebMatrix&Razor 에 모두 포함이 되어 있습니다.

아마도 처음 웹 개발에 접하시는 분들이 처음 갖는 고민은..? 웹 환경 구성/웹 프로토콜 및 통신의 이해/호스팅 등 복잡했던 초기 작업을 매우 효과적이고 간소화하여 신속하게 작업을 진행할 수 있는 장점이 있습니다.

   

WebMatrix 란 무엇인가요?

WebMatrix 는 약 15MB 의 용량으로 빠르게 웹 개발 환경을 갖출 수 있습니다. (단, .NET Framework 4.0 이 인스톨 되지 않았을 경우 약 50MB). 현재 WebMatrix 는 Beta 버전이며 이 링크를 클릭하시면 다운로드 받으실 수 있습니다.

이 웹 WebMatrix 에는 다음의 구성 요소가 포함이 되어 있습니다.

  • IIS Express
  • SQL Compact Edition
  • ASP.NET Extensions

그리고 Visual Studio 2010 또는 Visual Web Development 2010 Express 개발 도구를 이용하여 웹 개발 또는 커스터마이징을 하실 수 있습니다.

   

WebMatrix 는 쉽게 사용할 수 있게 설계가 되었습니다.

초기 웹 개발 환경은 웹 페이지를 만들기 위해 해야 할 일들이 많았습니다. 환경 구성/개발 환경 구성 등 말이죠.

WebMatrix 는 아래와 같이 매우 심플한 디자인으로 웹 개발의 시작을 빠르고 쉽게 수행할 수 있습니다. Site from Web Gallery 는 오픈 소스 웹 어플리케이션을 바로 설치하여 사용할 수 있고, Site From Template 으로 최적화된 환경에서 개발을 시작할 수 도 있습니다.

Site From Web Gallery 는 온라인에서 인기 있는 다양한 오픈 소스 웹 어플리케이션이 포함되어 있답니다. ASP.NET, PHP 의 오픈 소스 웹 어플리케이션이 포함되어 있으며, 설치나 배포가 매우 간단합니다.


그 중, Scott 님은 BlogEngine.NET 으로 예제를 보여주시네요. BlogEngine.NET 는 이미 예전부터 CodePlex 를 통해 오픈 소스로 공개가 되고 현재도 인기 있는 블로그 웹 어플리케이션입니다.

BlogEngine.NET 을 선택하고 Next 버튼을 클릭하면 이것을 설치하기 위한 컴포넌트를 체크하거나 다운로드 받습니다. 즉, 원클릭(One-Click) 으로 어플리케이션이 동작하기 위한 모든 환경을 스스로 구성한다는 얘기죠^^

PHP 어플리케이션의 경우 WordPress, Drupal, Joomla, Sugar CRM 등은 MySQL 이 필요한데, 개별적인 설치 없이 이런 환경도 자동으로 다운로드 받아 설치를 합니다.

간단하게 소프트웨어 사용권 동의(EULA) 를 클릭하면 바로 설치와 구성 작업을 시작합니다.

   

그리고 금새 설치와 구성이 완료가 되었지요^^

   

모든 구성이 완료되면, 아래와 같은 Overview 페이지가 나타납니다.

   

설치된 BlogEngine.NET 을 실행하기 위해서 아래의 Run 버튼을 클릭합니다. 인터넷 익스플로러, 크롬, 파이어폭스로 실행할 수 있고, Open in all browsers 로 여러 브라우저로 한꺼번에 실행할 수 있습니다.

   

자! 여태까지 클릭 클릭만 했는데, 아래와 같이 BlogEngine.NET 이 설치되고, 구성되고, 모든 구성이 완료가 됩니다.

   

초기 관리자 아이디와 비밀번호는 admin/admin 입니다. 관리자로 로그인 하셔서 블로그의 이름을 달아주시고, 블로그 저자 소개 등을 입력해 주시면, 곧바로 블로그를 운영을 준비하셔도 될 것 같습니다.^^

WebMatrix 는 오픈 소스 웹 어플리케이션을 커스터마이징 할 수 있는 약간의 개발 환경도 제공해 줍니다. 아래와 같이 소스 코드를 변경할 수 도 있고, Files 버튼으로 파일을 편집하거나 추가, 삭제를 할 수 있습니다.

   

이제 블로그를 운영하기 위해 배포와 호스팅을 해야 합니다.

WebMatrix 의 특징은 매우 경량화되었고 작업 환경이 통합된 장점을 갖습니다. 로컬 또는 원격 웹 서버로 배포할 때, FTP 또는 FTP/SSL 또는 Microsoft Web Deploy(MSDeploy) 를 이용하여 쉽게 배포가 가능합니다.

아래의 Publish 버튼을 클릭하면 배포 준비가 시작됩니다.

   

배포 세팅 화면은 아래와 같습니다. 서버의 기본 정보를 입력하고, 데이터베이스의 연결 문자열을 입력한 후에, Publish 버튼을 클릭합니다.

   

모든 준비가 완료되었고, Publish 버튼을 누르면 이제 배포를 시작할 준비가 완료 되었습니다.

   

이하.. 금일 Microsoft Korea 의 김대우 과장님께서 진행하는 WebMatrix&Razor 세미나에 참석하기 위해 이만 줄입니다. 다른 분들께서 더 알차고 재미있게 포스팅 해 주시리라^^