프로그래밍 언어 입문서가 아닌 프로그래밍 기초 개념 입문서
문과생, 비전공자를 위한 프로그래밍 입문책입니다.
jobGuid 꽃미남 프로그래머 "Pope Kim"님의 이론이나 수학에 치우치지 않고 실무에 곧바로 쓸 수 있는 실용적인 셰이더 프로그래밍 입문서 #겁나친절 jobGuid "1판의내용"에 "새로바뀐북미게임업계분위기"와 "비자관련정보", "1판을 기반으로 북미취업에 성공하신 분들의 생생한 경험담"을 담았습니다.
Posted by 친절한티스

벌써 두번째 연재네요. 재미없는 첫 번째 글에 많은 관심을 가져주신 분들께 감사드립니다. 여러 네임드 능력자분들과 같이 글을 쓰려니 괜히 쩌렙 인증하는 거 같고, 많이 후달립니다.

앞으로 올릴 글은 제가 최근 관심을 갖고 있는 주제이기도 한 병렬 프로그래밍에 대해 써볼까합니다. 분량이 좀 많다보니 연재식으로 될거 같습니다. 그리고 창희님과 번갈아가며 쓰게 될지도... ( 일단 떠밀어보기 )


바야흐로 세상은 대 멀티코어 시대
골드 D 인텔이 멀티코어로 세상을 평정하고 프로그래머들이 병렬 프로그래밍의 세계로 뛰어들어 세상은 대 멀티코어 시대에 돌입하였다!! ... 라는 되도 않는 드립을 쳐보려고 했지만 재미없네요.

병렬 프로그래밍을 찾아 떠나는 프로그래머 해적들

이제는 흔하다 못해 스마트폰에서까지도 멀티코어를 쓰는 시대입니다. 그에 맞춰 여기저기서 병렬 프로그래밍 얘기들이 흘러나오고 왠지 나도 병렬 프로그래밍 안하면 안될거 같은 기분이 마구마구 듭니다. 게다가 게임도 갈수록 고사양화 되고 있고 싱글 코어 활용만으로는 도저히 퍼포먼스도 안나옵니다. 멋지게 게임 만들어놨는데 CPU 사용률이 25%만 올라가있으면 왠지 손해보는 느낌까지 듭니다.

싱글 코어로 공짜밥 먹던 시절
멀티코어 시대 이전에 병렬 프로그래밍이 없었던 것은 아닙니다. 백그라운드 로딩이라든가 네트웤 통신에 많이 사용되고 있었고, 지금도 사용 되고 있습니다. 하지만 메인인 게임 로직부분은 거의 직렬 방식이었습니다. 과거에는 이 것 만으로도 충분했습니다. 게다가 CPU 제조사에서 속도를 업그레이드 해줄때 마다 자연스레 게임 퍼포먼스도 올라 갔습니다( CPU 제조사에 감사합니다~ ).

그러나 CPU 제조사의 이런저런 불편한 진실로 인해 속도 업은 미비해주고, 대신 코어 수로 떼우기 시작하게 됩니다. 게임은 갈수록 고사양이 되가는데 CPU 속도 업은 거의 없어지니 게임이 느려지기 시작합니다 ( 게임만이 아니지만 우린 게임 프로그래머이니 게임이라고 합시다 ) . 이를 두고 향간에서는 더 이상 공짜 점심은 없다!! ...라고 말하기 시작합니다.

누가 내 점심을 없앴는가?

멀티 코어 어떻게 써요? 
멀티 코어를 활용해야겠다고 다짐 했습니다. 어떻게 해야 멀티 코어 CPU를 활용할수 있을까? 옵션하나 탁~ 켜주면 내 프로그램이 멀티 코어로 작동했으면 좋겠습니다. ( 실제 멀티 코어 CPU가 어떤식으로 동작하는지 알고 싶으신 분은 [김민장님 저서인 프로그래머가 몰랐던 멀티코어 CPU 이야기] 한번 읽어보시기 바랍니다. ) 하지만 현실은 그렇게 쉽지 않습니다. 내가 만든 프로그램이 멀티 코어로 동작하기 위해서는, 병렬적인 프로그램을 만들어야지만, 멀티 코어 환경에서 병렬로 작동 됩니다.

말 장난 같지만 사실 입니다...


병렬 프로그램 어떻게 만들어요? 
멀티 코어 CPU의 경우 프로그램이 실행될때 병렬성을 체크해서 각 코어에 일을 할당 해줍니다. 만약 그런게 전혀 없다. 그러면 코어 하나에만 작업이 할당되서 프로그램이 작동하게 되는 것이죠. 몇몇 게임을 실행할때 4코어인데도 불구하고 CPU 사용률이 25%만 올라가는 이유가 바로 이 것 입니다. 그렇다면 어떻게 병렬성을 높일수 있을까요? 대표적인게 바로 멀티 스레딩입니다. 여러개의 스레드가 생성된 프로그램이라면 1번 코어에서 1번 스레드를, 2번 코어에서 2번 스레드 처리하는 식으로 병렬 처리를 하게 됩니다.

이것이 병렬 처리다!!

스레드만 추가 생성하면 끝? 
위에 적은 데로라면 스레드만 추가하면 CPU에서 알아서 병렬 처리를 해주겠네요. 스레드를 마구마구 생성해서 프로그램을 만들어봅니다. 아마 조만간 ㅅㅂ... 소리가 절로 나올겁니다. 정상 작동하는게 하나도 없어 보입니다. 왜그럴까요?

멀티 스레드를 이용한 프로그래밍을 할 때에는 많은 주의 사항이 있습니다. 대표적인 문제 중 하나로 꼽히는 것이 데이터 레이싱 입니다. 일반적으로 멀티 스레드는 동일 메모리 공간에서 작동합니다. 즉, 여러 스레드가 하나의 데이터에 동시 접근이 가능하다는 이야기입니다. 그렇게 되면 여러 스레드가 동일한 데이터를 읽고, 쓰다가 원치 않는 값  변조가 일어나게 됩니다. 밑의 그림은 그 상황 예시입니다.

 
1번과 2번 스레드가 x값을 참조하고, 값을 바꿔 써넣는 코드입니다. 1번과 2번 스레드는 비동기로 동작하기 때문에 어떤 스레드가 먼저 x값을 참조하고 값을 바꿀지 모릅니다. 그래서 x의 최종 결과 값이 #1, #2, #3중 어느 결과로 나올지 알 수 없습니다.

문제는 이것만이 아닙니다. 데드락 문제도 있고, 코어 수만큼 스레드를 어떻게 분배할 것인지도 문제고, 생성된 스레드들은 또 어떻게 관리 할지도 문제입니다. 병렬 프로그래밍을 해보려다 그 앞에 산재해 있는 문제들때문에 제대로 해보지도 못하고 포기하게 생겼습니다.

쉬운 방법 없을까? 
좀더 쉬운 방법이 없을까? 눈을 돌려봅니다. 세상에는 똑똑한 분들이 많습니다. 멀티 코어 CPU가 발전하는 만큼 이를 쉽게 사용할 수 있게 해주는 라이브러리들도 발전하고 있습니다. OpenMP, TBB, PPL등이 그것입니다. 이들 라이브러리를 이용하면 직접 스레드를 관리하거나 분배하는 수고 없이 수월하게 병렬 처리를 할수 있도록 도와 줍니다.

간단하게 배열에 있는 수를 더하는 로직을 병렬로 처리 해보도록 하겠습니다. 직렬 처리 방식으로 로직을 구성 한다면 이런 모양 일겁니다.
for( int i = 0; i < 5000; ++i )
	fNumSum += fNum[ i ];
참으로 단순한 로직입니다. 5000개의 배열을 가지고 있는 fNum의 임의수들을 전부 다 더하는겁니다. 이걸 병렬로 처리 한다고 생각해봅니다. 그전에 위에서 얘기한 멀티 스레드의 문제점을 다시 떠올려봅니다. 그냥 스레드를 여러개 생성해서 위의 로직을 수행한다고 하면, 데이터 레이싱이 일어나 엉뚱한 합산 값이 나올겁니다. 이를 방지하려면 스레드에 맞게 배열을 분배 해주어야 합니다. 스레드를 2개 생성 한다면 1번 스레드는 0~2499, 2번 스레드는 2500~4999 식으로 말이죠. 그리고 작업을 수행 후 서로 합산 값을 더하면 원하는 결과가 나오게됩니다.

그런데 이것을 직접 수동으로 한다면, 스레드도 직접 생성해주고, 모든 스레드가 작업을 수행할때까지 대기했다가 작업이 끝나면 Join 시켜주고, 값 합산 해야하고, 만약 CPU 코어 수에 맞게 스레드 생성도 해주겠다 하면... 손이 가는게 이만 저만이 아닙니다. 단순한 합산 로직 하나 만드려고 들이는 정성이 배 보다 배꼽이 더 큰격입니다.

정말 이런 짓을 매번 하라고??

그럼 TBB가 출동 한다면 어떨까요??
// 병렬 처리를 위한 바디 클래스
// TBB 쓰면 그냥 이런 식으로 구성된다라는 것을 알리기 위함이므로 코드 설명은 생략
class CFoo 
{
private:
	float* m_fElement;

public:
	float m_fSum;
	void operator()( const blocked_range<size_t>& r )
	{
		size_t end = r.end();
		for( size_t i = r.begin(); i != end; ++i )
			m_fSum += m_fElement[ i ];
	}
	CFoo( CFoo& pSplitFoo, split ) : m_fElement( pSplitFoo.m_fElement ), m_fSum( 0 ) {}
	CFoo( int a[] ) : m_fElement( a ), m_fSum( 0 ) {}
	void join( const CFoo& pSplitFoo )
	{
		m_fSum += pSplitFoo.m_fSum;
	}
};

// TBB의 parallel_reduce를 이용해 fNum의 5000개 배열의 값들을 합산
CFoo foo(fNum);
parallel_reduce( blocked_range<size_t>( 0, 5000 ), foo );
코드 어디를 봐도 스레드를 생성하고, 작업을 분배 해주는 곳이 없습니다. 다~ 자동입니다. 알아서 코어수 만큼 스레드를 할당해주고, 각 스레드에 알맞은 작업량을 할당해줍니다. 작업자는 스레드 관리에 대해 전혀 신경쓸게 없습니다. 완전 좋죠~!! 짱입니다!! ( 물론 세세한 옵션등이 있지만 일단은 신경끕니다 ).

병렬 프로그래밍. 참 쉽죠?
TBB를 사용하니 병렬 프로그래밍이 엄청 쉬워진 것 같습니다. 하지만 안쉽습니다. 절대 안쉬워요. 조금이라도 병렬 프로그래밍 해보신 분이라면... 이거 참 병맛이다. 라고 말씀하실 겁니다. 아무리 툴이 좋아지고, 라이브러리가 좋아졌어도, 그걸 사용하는 사람은 기본적으로 직렬적으로 생각합니다. 동시에 처리될 부분을 모두 염두해가며 프로그래밍을 할 수 있는 사람은 극히 드뭅니다. 왜 난 이런 것도 못하지? 자책하지 마세요. 그게 정상입니다. 할수 있는 사람들이 특이한겁니다.

안 쉬워요.

To Be Continued....
다음 강에는 게임 프로그래밍에 적용하는 병렬 프로그래밍에 대해 좀더 다뤄볼게욤~
아마도... 

댓글을 달아 주세요

  1. 이전 댓글 더보기
  2. Favicon of https://gamedevforever.com ozlael 2012.01.05 23:57 신고  댓글주소  수정/삭제  댓글쓰기

    병렬을 순간 병맛으로 읽었음 ㅋㅋ 이 어려운 병렬이라는 주제라니 !!! 존경함다 ㅠㅠ

  3. Favicon of https://gamedevforever.com 라오그람 2012.01.16 19:02 신고  댓글주소  수정/삭제  댓글쓰기

    크 TBB가 나오는군요! 책보고 아 ㅅㅂ 나는 저렇게 설계가 안되는데...라고 좌절했었다죠ㅠㅠ 다음 연재 기대됩니다!!

  4. Favicon of https://gamedevforever.com cagetu 2012.01.16 19:18 신고  댓글주소  수정/삭제  댓글쓰기

    멋져요~ ㅎㅎ

  5. 책읽는잉여 2012.01.18 10:24  댓글주소  수정/삭제  댓글쓰기

    멋진 강좌네요~

  6. 구타후설득 2012.01.18 10:35  댓글주소  수정/삭제  댓글쓰기

    와..좋은데요^^

  7. Silverchime 2012.01.18 11:19  댓글주소  수정/삭제  댓글쓰기

    재미있네요... 기대할께요 두근두근~

  8. Favicon of http://Junios.net Junios 2012.01.18 12:41  댓글주소  수정/삭제  댓글쓰기

    강좌 잘 보겠습니다. ㅎㅎ. 그래도 공짜 점심이 좋아요 ㅋ

  9. Favicon of https://gamedevforever.com 대마왕J 2012.01.18 13:09 신고  댓글주소  수정/삭제  댓글쓰기

    이런거 보면 프로그래밍 하고 싶다능 두근두근

  10. 돼지고기 2012.01.18 13:28  댓글주소  수정/삭제  댓글쓰기

    드랍대마왕~ 완전 잘보았습니다.^_^

  11. 죠쉬 2012.01.18 14:20  댓글주소  수정/삭제  댓글쓰기

    수고 쩔어엽!
    잘 보았습니답.
    특히 젖절한 짤방들 알흠 다왔사와~요.

  12. Favicon of https://gamedevforever.com 끼로 2012.01.18 15:35 신고  댓글주소  수정/삭제  댓글쓰기

    다음꺼가 빨리 나왔으면 좋겠습니다!! 병렬프로그래밍 너무 어려워요 ㅠㅠ 티스님만 따라갈께요..

  13. Favicon of http://bluekms21.blog.me 크로스 2012.01.18 15:59  댓글주소  수정/삭제  댓글쓰기

    오.. 이거 또 좋은 강좌가 올라오기 시작하는군요 +ㅂ+
    음.. 그런데 TBB라는건 처음 보는데.. 좀 자세한 정보를 얻을 수 있는 사이트라도 없을까요?
    설마 내부에서 엄청나게 크리티컬 섹션같은걸 걸어버리면서 처리하는 라이브러리일 뿐인가요?

  14. 알콜코더 2012.01.18 17:23  댓글주소  수정/삭제  댓글쓰기

    이런 병맛 프로그래머.. 티스군..
    그냥 자동으로 되게 해줘!!

  15. Favicon of https://gamedevforever.com 김포프 2012.01.19 04:16 신고  댓글주소  수정/삭제  댓글쓰기

    TBB가 아마 Task System기반이죠? PS3가 SPU 짓을 하고 나서부터 더욱 주목받기 시작한 시스템인데... .NET 4.0의 Parallel 라이브러리도 이거 지원하면서 많이 괜찮아진거 같아요. TBB가 LGPL이나 MIT 라이센스만 되었어도 더 좋았을텐데...라고 생각..

    아님 boost에서 조만간 task system을 지원할지도?

    • Favicon of https://gamedevforever.com 친절한티스 2012.01.19 09:37 신고  댓글주소  수정/삭제

      부스트 기대!! 해주겠죠~!!

    • Favicon of http://www.sysnet.pe.kr kevin 2012.01.19 10:40  댓글주소  수정/삭제

      포프님.... .NET 4.0 의 Parallel 이 TBB 를 지원한다는 것을 어디서 보신 건지 알 수 있을까요? 개인적으로 처음 들어본 소식이라서요.

      혹시... .NET 4.0 의 TPL(Task Parallel Library) 와 TBB 를 혼동하신 것이 아닌가 싶습니다.

    • Favicon of https://gamedevforever.com 김포프 2012.01.20 02:29 신고  댓글주소  수정/삭제

      TBB가 아니라 Task System을 의도한 것이었는데 다시 읽으니 헷갈리게 썼군요. 죄송합니다 ^_^

      TBB나 .Net 4.0의 Parallel(이게 TPL이에요? 이름은 첨 들었네요)이 둘다 내부적으로 Task System을 구현한다는 말이었지요~

  16. Favicon of http://rhea.pe.kr/ Rhea 2012.01.19 12:04  댓글주소  수정/삭제  댓글쓰기

    트, 특이한 사람이 되고 싶습니다!!

  17. Favicon of https://gamedevforever.com denoil 2012.01.19 23:03 신고  댓글주소  수정/삭제  댓글쓰기

    와~병렬 프로그래밍! openMP가 아닌 다른것이군요! 다음편기대해봅니다^^

  18. Favicon of https://gamedevforever.com ozlael 2012.01.20 12:37 신고  댓글주소  수정/삭제  댓글쓰기

    우와 난 과외해줘요~

  19. smilejp 2012.01.30 10:07  댓글주소  수정/삭제  댓글쓰기

    tbb 라이센스 관련 궁금한것이 있습니다.

    별생각없이 사용하고 있었던건데 댓글을 보다보니 상용에 그냥 쓸수없다는 얘기들이 나와서..
    머지.. 쓸수없는건가.. 생각하고 검색을..

    http://threadingbuildingblocks.org/ 여기 들어가보면 페이지 오른쪽에
    Licensed under GPLv2 with the runtime exception. 이라고 적혀있습니다.

    runtime exception 이 멀까 하고 가보니
    As a special exception, you may use this file as part of a free software
    library without restriction. Specifically, if other files instantiate
    templates or use macros or inline functions from this file, or you compile
    this file and link it with other files to produce an executable, this
    file does not by itself cause the resulting executable to be covered by
    the GNU General Public License. This exception does not however
    invalidate any other reasons why the executable file might be covered by
    the GNU General Public License

    요렇게 나오고요.. 그럼.. dll로 쓰는건 괜찮은거 아닌가요?? 제가 잘못 이해하고 있는가 해서요..

    구글님의 검색을 해보면.. dll로 사용하는건 괜찮다는 글(http://rein.kr/blog/archives/1817)이
    발견되기도 해서.. 궁금합니다! 알려주세요~ 아.. 라이센스ㅠ

  20. Favicon of http://www.ahappydeal.com/wholesales-owl-fleece-fabric.html owl fleece fabric 2012.06.25 17:47  댓글주소  수정/삭제  댓글쓰기

    ㅋㅋ과제 시작전에 들어와서 글남긴다. 내가 1등인가 ?,?

  21. Favicon of https://ezkorry.tistory.com EzKorry 2014.08.11 14:54 신고  댓글주소  수정/삭제  댓글쓰기

    재밌어요! 병렬 프로그래밍에 대해 아무것도 몰랐는데 슬슬 감이 잡히는 기분이 드네요..ㅎㅎ