도플광어님의 '유니티엔진의 coroutine & yield 1편. FSM의 습격' 을 보면 코루틴에 대한 자세한 설명이 나옵니다.
그렇다면!! 이렇게 편한 코루틴을!! C++에서 쓸 수는 없을까?!
(제한적이긴 하지만)가능합니다!!
사실 C++ 자체로만은 만들기가 어렵고요.. goto문으로 만드는건 자체 스택을 가지지 않기 때문에 위험성도 있고 여러가지 문제가 있죠
그런데 Win32 API에는 Fiber라는 녀석이 존재합니다. Fiber는 유저 레벨 쓰레드 라고도 불리는 녀석인데요.
동작하는 방식이 코루틴과 거의 흡사합니다. 그럼 이녀석을 이용해서 코루틴처럼 만듭시다!!
라고 하면 너무 힘들겠죠.. 사실 이미 그렇게 만들어서 공개된 라이브러리들이 존재합니다!!
그 중에서 제가 소개하려고 하는 것은 boost.coroutine입니다.
일단 다운로드부터 받아봅시다.
https://github.com/boost-vault/Concurrent-Programming/blob/master/boost-coroutine-2009-12-01.tar.gz
boost 코루틴은 boost 공식 라이브러리에 포함된 라이브러리가 아니어서 따로 받아주어야 합니다.
boost의 폴더구조를 그대로 사용하고 있기 때문에 받은 후에 boost 폴더에 덮어씌워주면 됩니다.
사용도 상당히 간단합니다. 코루틴 객체를 만들고 코루틴 객체를 실행해주고 코루틴객체에서 self.yield를 호출해줄 수 있습니다. Fiber니 뭐니 그런건 그닥 신경안써도 되죠. 사실 windows에서만 Fiber를 쓰고 다른 OS에서는 다른 API로 작동하게 구현이 되어있습니다. 물론 모든 OS 버전을 지원하진 않습니다.
{
printf( "첫번째\n" );
self.yield();
printf( "두번째\n" );
self.yield();
printf( "세번째\n" );
self.yield();
printf( "네번째\n" );
self.yield();
printf( "다섯번째\n" );
}
int _tmain(int argc, _TCHAR* argv[])
{
boost::coroutines::coroutine<void ()> coro( TestFunction );
printf( "첫번째 실행\n" );
coro();
printf( "두번째 실행\n" );
coro();
printf( "세번째 실행\n" );
coro();
printf( "네번째 실행\n" );
coro();
printf( "다섯번째 실행\n" );
coro();
if( coro.exited() )
{
printf( "끝!\n" );
}
}
위 코드의 결과는 아래처럼 나오게 됩니다.
self.yield()를 호출할때마다 코루틴을 실행해준 위치로 빠져나오고 다시 코루틴을 실행해주면 마지막으로self.yield()를 호출해준 다음 명령부터 실행되는 것을 확인할 수 있습니다.
리턴값이 있는 코루틴을 사용하는 경우에는 다음과 같이 할 수 있습니다.
int TestFunction( coro_type::self& self )
{
self.yield( 2 );
self.yield( 4 );
self.yield( 6 );
self.yield( 8 );
return 10;
}
int _tmain(int argc, _TCHAR* argv[])
{
coro_type coro( TestFunction );
printf( "%d\n", coro() );
printf( "%d\n", coro() );
printf( "%d\n", coro() );
printf( "%d\n", coro() );
printf( "%d\n", coro() );
if( coro.exited() )
{
printf( "끝!\n" );
}
}
역시 이 코드의 결과는 다음과 같습니다.
self.yield( 리턴값 ) 을 호출해주면 코루틴을 호출한 곳에서 리턴값을 받아서 사용할 수 있습니다.
코루틴이 처음 생성될때 추가로 인자값을 넣어줄 수도 있습니다.
int TestFunction( coro_type::self& self, int number )
{
number += 2;
self.yield( number );
number += 2;
self.yield( number );
number += 2;
self.yield( number );
number += 2;
self.yield( number );
number += 2;
return number;
}
int _tmain(int argc, _TCHAR* argv[])
{
coro_type coro( boost::bind( TestFunction, _1, 10 ) );
printf( "%d\n", coro() );
printf( "%d\n", coro() );
printf( "%d\n", coro() );
printf( "%d\n", coro() );
printf( "%d\n", coro() );
if( coro.exited() )
{
printf( "끝!\n" );
}
}
역시 마찬가지로 다음과 같은 결과가 나올 것입니다.
물론 처음 말한것처럼 다른 언어에서 보여주는 정도의 완벽한 코루틴을 구현할 수는 없습니다. 그리고 제한적입니다.
특히 boost.coroutine은 윈도우즈 서버 2008 이상의 OS나 윈도우즈 비스타 이상의 OS에서만 정상적으로 동작합니다.
그래서 클라이언트에서는 사용하기 어렵습니다..하지만 서버에서라면 쓸 수 있습니다. (네 저희는 윈도우 서버 2008을 사용합니다..) 그리고 사실 클라이언트에서보다 서버에서 더 효과적이라고 생각됩니다.
사실 이 뒤에 더 이어서 이것저것 써보려고 했지만.. 생략... 죄송합니다 노느라..
'프로그래밍' 카테고리의 다른 글
Fast sine approximation (11) | 2012.07.12 |
---|---|
PC에서 3D 입체 영상 게임 개발하기 #4 (1) | 2012.07.09 |
그래픽스 프로그래머 (17) | 2012.06.28 |
툴의 꽃 프러퍼티 그리드를 사용해보자 #2 ( PropertyGrid for WPF ) (3) | 2012.06.27 |
툴의 꽃 프러퍼티 그리드를 사용해보자 ( PropertyGrid for WPF ) (15) | 2012.06.22 |