jobGuid 꽃미남 프로그래머 "Pope Kim"님의 이론이나 수학에 치우치지 않고 실무에 곧바로 쓸 수 있는 실용적인 셰이더 프로그래밍 입문서 #겁나친절 jobGuid "1판의내용"에 "새로바뀐북미게임업계분위기"와 "비자관련정보", "1판을 기반으로 북미취업에 성공하신 분들의 생생한 경험담"을 담았습니다. 3ds Max를 사용해서 게임용 3D 캐릭터를 셋업하는 방법
이를 위해 오랜 실무를 경험해 온 저자의 고급 노하우들이 공개
위 내용은 GameDevForever의 저자분들의 홍보를 위하여 운영진 자체적으로 올린 광고이며 일체의 수익이 없습니다.(밥좀사줘요~)
Posted by 끼로

도플광어님의 '유니티엔진의 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 버전을 지원하진 않습니다.


void TestFunction( boost::coroutines::coroutine<void ()>::self& self )
{
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()를 호출해준 다음 명령부터 실행되는 것을 확인할 수 있습니다.


리턴값이 있는 코루틴을 사용하는 경우에는 다음과 같이 할 수 있습니다.


typedef boost::coroutines::coroutine<int ()> coro_type;

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( 리턴값 ) 을 호출해주면 코루틴을 호출한 곳에서 리턴값을 받아서 사용할 수 있습니다. 


코루틴이 처음 생성될때 추가로 인자값을 넣어줄 수도 있습니다.

typedef boost::coroutines::coroutine<int ( int )> coro_type;

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을 사용합니다..) 그리고 사실 클라이언트에서보다 서버에서 더 효과적이라고 생각됩니다.



사실 이 뒤에 더 이어서 이것저것 써보려고 했지만.. 생략... 죄송합니다 노느라..

댓글을 달아 주세요

  1. Favicon of http://lunapiece.net Lyn 2012.07.02 21:04 신고  댓글주소  수정/삭제  댓글쓰기

    XP면 충분하죠 ㅋㅋ

    2000 지원할것도 아니고 =_=;(애초에 DX부터 문제가 ...)

    • Favicon of http://gamedevforever.com 끼로 2012.07.02 21:15 신고  댓글주소  수정/삭제

      아.. 기본적인 Fiber API는 XP이상부터 지원한다는거 때문에 글을 잘못 썼네요;; 몇몇 API때문에 boost coroutine은 비스타부터 정상 작동합니다.. IsThreadAFiber 라던지 몇몇 비스타부터 제공되는 API를 사용하거든요 ㅎㅎ; 본문도 수정해놔야겠네요.. 깜짝놀랬네..

    • Favicon of http://lunapiece.net Lyn 2012.07.09 10:10 신고  댓글주소  수정/삭제

      아... 오타셧군요 ㅎㅎ;

      전 얼마전까지 2008 R2를 쓰는 회사에 있었어서 맘껏 최신 API 다 끌어다 썼었는데 ㅠ.ㅠ

      지금은 리눅스 Orz



티스토리 툴바