Main

November 24, 2005

미니덤프를 사용하자!!

 이번엔 진짜다. 미니덤프를 꼭 사용하자!

 대부분의 어드밴스드 프로그래머(advanced programmer)-_-들은 프로그램의 비정상 행동에 대처하기 위해 콜스택(callstack)을 캡쳐하여 버그(Bug)를 잡을 것이다. 비정상 종료됐을때 콘솔이나 파일에 기록된 콜스택과 레지스터(register)의 정보를 토대로 디버깅하는 방법에 대한 테크닉들은 널리 퍼지고 잘 알려져있다. MSDN의 Bugslayer나 codeguru, codeproject 혹은 google에서 callstack으로 검색하면 산더미 만큼 나올 것이다. 이 콜스택에 대한 정보를 이용하면 일반적인 대부분의 비정상 종료를 대해 잡을 수 있다. assert를 이용해서 단순히 소스파일이름과, 줄번호만 가지고 잡던 시절에 비하면 이 것만으로도 디버깅을 위한 축복이다.

 이 포스팅의 주인공 미니덤프(Minidump)는 디버깅을 수월하게 하기위해, windows xp 이후에 등장하였다. (엄밀히 말하면 2k와 xp사이에 ms가 내부에서 디버깅에 사용하던 것을 공개한듯 하다.) 2k를 포함한 이전의 윈도우즈에서 이를 사용하려면 최신버전의 dbghelp를 사용하면 된다. 미니덤프는 실제로 비정상 종료가 일어났을때의 일부 메모리에 대한 덤프를 저장하는 것이다. 여기에는 대부분의 쓰레드 정보, 각 쓰레드의 콜스택정보를 포함한다. 사실 일반 프로그램이라면 미니덤프까지도 필요 없고 비정상 종료가 발생한 콜스택만 가지고도 대부분의 디버깅이 가능하다. 하지만, 멀티쓰레디드 프로그램에서라면 상황은 달라진다. 프로그램이 그냥 죽어버리면 다행이겠지만, 프로그램은 죽지 않았는데 쓰레드끼리의 동기화 문제로 정상적으로 프로그램이 동작하지 않는 상황이 발생하는 것이다. 이에 스타베이션(굶주림,starvasion)이나 데드락(deadlock) 문제가 포함된다.

 미니덤프가 평소에 별 도움을 주지 않아서 덤프만 남기고 잘 살펴보지 않으며 등한시 하였는데, 오늘 한달간 나를 괴롭히던 '데드락'을 미니덤프를 이용하여 잡았다. 마왕을 물리쳤다! -_-

 최근의 업계 동향으로 따진다면, 쓰레드끼리 동기화를 해야하는 멀티쓰레디드 프로그래밍 패러다임 자체에 대한 회의가 짙은듯하다. 최근이라고 하기도 뭐하고 꽤나 오래전부터 이 '능률적인' 멀티쓰레디드 프로그램을 만드는 것은 어렵다고 알려져있다. 사실 멀티쓰레디드 프로그래밍은 조낸 쉽다. 그냥 동기화 객체를 쳐 발르면 성능하고는 관계없이 정상적인 동작을 수행한다. 하지만 '능률적인' 멀티쓰레디드 프로그램은 확실히 어렵다. (이러한 추세를 반영하는 것으로써 OpenMP가 있다. VS.Net 2k5에 포함되는걸로 알고있다.)

 이것과 관계된 약간의 팁이라면, win32 structured exceptional handling을 이용하여, 아무때나 특정한 순간에 callstack과 minimap을 찍는 것이 가능하다. 그냥 잘못된 연산을 수행하고 recovery하면 된다. 자세한 문법은 msdn에 잘 나와있을 것이다. 위의 '마왕'은 데드락에 걸렸다고 판단이 났을때에, 미니덤프를 뜨고 그 미니덤프를 이용하여 각 쓰레드의 상태를 살펴보니 전부 락을 거는 소스코드위치에 쓰레드가 대기하고 있는 것을 보고 발견하였다. 다들 젓가락 한개씩 들고 있었다. -_-

fin.

November 21, 2005

하이퍼쓰레드를 사용하자!!

p4pht.jpg   HYPERTHREAD!

 사실 제목과 반대다.

 zdnet기사에 hyperthread가 오히려 퍼포먼스 저하를 야기한다는 기사가 실렸다. intel에서 하나의 cpu값으로 이론상 두배의 성능약 1.3배의 성능을 끌어낸다고 자랑하여 팔아왔던 hyperthread 기술은 쓰레기임이 판명났다. 이유인 즉슨, hyperthread가 L1과 L2를 공유해서 쓰는데 이 때문에 서로에 대한 배려가 없이 L1 과 L2을 thrash해 버린다는 것이다. 특히, 서버용 프로그램에서 hyperthread를 끄는 것보다 오히려 성능저하가 난단다. 이런 쓰레기 같은 기술이 있나! -_-; 확실한 점은, SQL Server는 hyperthread enabled된 컴퓨터에서 풀로드 시에 거의 성능 저하가 있다는 점을 알아두어야 한다.

 금년 초에는 L1 & L2를 공유하는 것으로 인한 보안 문제(예를 들어 중요한 서버인데, 쓰레드 하나가 그 서버의 계정정보를 읽는 중이고 다른 한 쓰레드는 웹서버쓰레드일때, 웹서버 쓰레드(anonymous 권한)가 계정정보 쓰레드(어드민 권한)의 메모리를 볼수 있는 것 같은 문제)도 있었고, 일단 서버용 프로그램을 주로 돌리는 컴퓨터라면 hyperthread를 일단 끄는게 좋을 듯하다. hyperthread의 이점을 살리려면 메모리를 아껴쓰면 되겠다. 보통은 speed를 위해 memory를 많이 사용해서 trade-off 하는데 hyperthread가 켜져있다면 speed를 위해 memory를 사용하면, memory는 많이 사용하는데 속도는 그대로인 경우가 발생할지도 모른다.-_-

November 01, 2005

Visual Studio 2k5, SQL Server 2k5 - 발매

vs_beta.jpg

 아직 패키지로 나온것은 아니고 msdn 구독자들은 지금 다운로드 가능하다. 예전에는 그때그때 새 버전의 개발툴을 테스트해보곤 했는데 이번은 발매되고 나서 처음으로 깔아보게 생겼다. 현재 내가 사용하는 개발툴이 vc2k3+sql2k인데 개발툴 두가지가 동시에 업그레이드 되는 것 같이 왠지 모르게 뿌듯하다. :)

 그나저나 점점 ms는 c++/cli 쪽을 계속 만들고 새로운 기능들을 추가하는것 같다. 무척 궁금하다, C++/CLI 사용하는 사람들이 그렇게 많은가? 개인적인 느낌은 ms가 자기네 세상을 만들려고 사용자들을 C++/CLI로 끌어들이려는 거 같다. 왠지 모르게 짜증나는 느낌-_-; 전에 한번 C++/CLI로 테스트 윈도 클라이언트를 만들려고 해본적이 있는데, C++라이브러리를 사용하려하다가 C++단의 콜백함수문제로 포기한적이 있다.

   Bjarne Stroustrup사마는 이것에 대해 어떤 생각을 갖고 계실지 궁금하다. (갈때마다 느끼는 압박은 단연 I designed and implemented the C++ programming language. 라는 문구, 지구에서 단 한명만이 쓸수 있는 말이다. )

 추후에 여력이 된다면 간략하게라도, vc2k5에서 추가된 기능들에 대해 써봐야겠다. 어서 빨리 윈도플랫폼에 강력한 경쟁 컴파일러가 등장하기를 기원한다.

 

September 25, 2005

Sudoku 해결기, 생성기 Part2

관련포스트:  Sudoku 생성기

 아무 모양의 Sudoku를 생성할수 있게 바꾸었다. (귀찮아서 상수변경으로 재컴파일을 해야 함)  바꾸어야 하는 것은, 블럭의 크기 N(3이면 블럭이 3x3)과 블럭으로 이루어진 전체 보드의 크기K(N이3이고 K가3이면 일반 9*9의 Sudoku가 된다)

 어차피 생성기 자체가 없는 수를 찾아서 채우도록 되어 있었으므로, 간단하게 문제를 풀수 있게 만들었다.

 찾아보니, 전체적인 크기자체는 그대로 두고 안의 블럭 모양이 정사각형이 아닌 다른 모양(Polyomino, 테트리스의 4개의정사각형으로 이루어진 모양 같은 것)으로 이루어진 것도 있는것을 알았다. 하지만 귀찮아서 생략-_-.

 참고로 4x4생성기까지는 실시간으로 생성되지만, 5x5생성기는 잘풀리는 경우 1초에도 생성되지만, 잘안풀리는 경우는 무척 오래걸려서 얼마나 걸리는지 체크해보지 못했다. -_- 대표적인것으로 랜덤시드에 0을 넣으면 3초만에 생성된다. 

solved!.png
 당신도 상위1%안에 들수 있다!-_- http://www.websudoku.com/

September 24, 2005

Sudoku 게임과 생성기

 Sudoku라는 퍼즐 게임이 있다. 영국에서 미칠듯한 스피드로 사람들이 풀어제끼고 있다고 한다. 뭐... 퍼즐을 좋아하기는 하지만, 단순한 스타일이라서 아직은 얼마나 재미있는지는 모르겠다. 그러다가 어느분이 생성알고리즘에 대해 거론하였기에 한번 만들어봤다.

 원래 난이도 까지 넣어서 화면으로는 문제를 보여주고, 파일로 해답을 저장하는 것 까지 만들려고 했으나 친구생일약속으로 지금 바로 나가봐야하므로 보류.

 9*9의격자에 1~9까지 숫자가 들어가는걸 생각한다면 (81^9승개의 조합) 끔찍하게도 많은 조합을 계산해야 하는거 같은데, 실제로 해보니 숫자가 들어가는 조건이 까다로워서 순식간에 조합을 만들어낸다. 9*9격자에 저러한 룰로써 숫자를 채우는 조합이 많지 않을줄 알았는데 돌려보니 정말 많다. 결과 셋을 1기가 가량 만들어내는것을 보다가 껐다. :) 알고리즘은 단순한 Brute Force-_- 재귀호출을 하지 않고 stack을 사용했다.

 사용법은 "Sudoku 랜덤시드(대강 0~21억사이의 수) 원하는수도쿠결과갯수"이다. 랜덤시드가 같으면 같은 결과를 출력해낸다. 결과갯수에 0을 집어넣으면 모든 조합을 출력한다. (실행이 끝나는데 얼마나 걸릴지 모른다. -_-)

fin.

August 27, 2005

Yet Another C++ DB Wrapper-Wrapper

DB를 사용하는 코드는 깔끔할 수가 없다. 이것은 C++에서 스크립트를 사용하는 것과 어느정도 이유를 공유한다. 서로 데이터 형을 처리하는 방식이 다르기 때문이다. 따라서 어떠한 언어에서 다른 언어(DB포함)의 함수를 호출하려면(혹은 데이터를 읽어오려면) 그에 맞게 파라메터와 결과값을 읽어서 사용할 언어로 변환해야 한다. 운이 좋아 거의 비슷하다면 이러한 수고를 덜수가 있다. 그리고 또한가지 이유는, 변수나 함수를 호출할때 그것의 이름에 대한 것이다. C/C++만 쓸때는 컴파일러에서 우리가 코드에서 스트링으로 함수이름이나 변수이름을 치면 컴파일러가 알아서 주소값으로 변환해주지만, 다른 언어(혹은 DB)를 사용할때는 이러한 모든 작업 또한 직접해주어야 한다.

아무튼, 이러한 이유로 db를 접근하는 코드는 무척이나 지저분하다. 그래서 이러한 일을 어느 정도 해주는 여러가지 라이브러리가 있는데, 내 요구사항을 만족시키는 것이 없어서 두가지 라이브러리를 혼합해서 만들어 사용하고 있다.

OTL + DTI = OTLA (oTL Assist: 나의 네이밍센스-_-)

1. OTL은 c++에서의 db 접근을 string으로 쿼리를 만들어, c++ iostream이 형식을 따와서 stream에서 '<<'와 '>>'연산자를 이용하여 DB 데이터를 fetch한다. string 으로 쿼리를 작성해야 하는 것 때문에, 좋은 라이브러리는 아니다. 하지만, 이 라이브러리의 장점은 odbc 코드를 거의 다 제거 한다는 것에 있다.

2. DTI는 CUJ 2005/04에서 우연히 발견하였다. 일단, 구현된 코드만 본다면 적절한 매크로를 이용하여 깔끔한 코드를 자랑한다. 물론 odbc api는 외부로 하나도 드러나지 않는다. 그러나! 상용에서 사용할만큼 코드의 완성도가 높지 않다. StoredProcedure 호출이 불가능하다.

3. 그래서 DTI 코드 스타일로 OTL을 감쌌다. 크게 세가지 작업이 되었다. 첫째는 백엔드를 OTL을 사용하고 외부 인터페이스는 DTI로 클래스를 모두 새로 작성하였다. 두번째는 select, update 등의 작업을 할때, WHERE절에 대한 바인딩을 따로 사용할 수 있게 하였다. 세번째는 StoredProcedure 호출하는 클래스를 새로 작성하였다.

다음은 결과적으로 만든 SP 호출 코드 예제다.

[StoredProcedure code.1]

-- create
CREATE PROCEDURE dbo.p_GetAccountInfo
 @acct_uid  INT, 
 @avat_name  varchar(50) OUTPUT,
 @return_code INT OUTPUT
AS
 SET NOCOUNT ON
 
 SELECT @avat_name = avat_name
  FROM dbo.Avatars
  WHERE avat_uid = @acct_uid
  
 IF ( @@ROWCOUNT = 1 )
 BEGIN
  SET @return_code = 0
 END
 ELSE
 BEGIN
  SET @return_code = 1015
 END
--END 
RETURN

[StoredProcedure 호출 바인더 code.1]

struct SP_p_GetAccountInfo
{
 // INPUT
 Account_UID_t         acct_uid;
 // OUTPUT
 compat::TFixedString<MAX_AVATARNAME_SIZE>  avat_name;
 int            return_code;
 BEGIN_OTLA_BINDING    
  OTLA_BIND_ATT_COLUMN_NAME( oTLA::SP_IN_ARG,  acct_uid, "acct_uid" )
  OTLA_BIND_ATT_COLUMN_NAME( oTLA::SP_OUT_ARG, avat_name, "avat_name" )
  OTLA_BIND_ATT_COLUMN_NAME( oTLA::SP_OUT_ARG, return_code,"return_code" )
 END_OTLA_BINDING
};
 

[StoredProcedure 호출 코드 code.1]

 TAutoPayback<IDBUpdater> updater = spjam_db.GetAutoUpdater();
 try
 {
  oTLA::StoredProcedure< SP_p_GetAccountInfo > sp_get_account_info;
  sp_get_account_info->acct_uid.uid = 2000100; // 파라메터 입력
  sp_get_account_info.Open( updater.Get(), "p_GetAccountInfo" ); // SP 호출
  T2_LOG(T_CONSOLE).Printf( "p_GetAccountInfo - avat_uid[%d] avat_name[%s] return_code[%d]\r\n",
   sp_get_account_info->acct_uid.uid,
   sp_get_account_info->avat_name.c_str(),
   sp_get_account_info->return_code
   ); // 결과 출력
 }
 catch ( oTLA::OTLA_Error& p )
 {
  T_LOGF( T_ERROR, "#2 %s\r\n", p.what() );
  updater->Rollback();
  return;
 }
 

ps. 공개는 할수도 안할수도 -_-

* 참조문서: CUJ 2005/04

August 24, 2005

visual studio.net 2k3: some error message

1. 에러메세지: "VC 패키지를 사용할 수 없거나 등록하지 않았습니다."
-> 해결법: http://support.microsoft.com/default.aspx?scid=kb;en-us;320427
2. DTE.OLB를 로드할수 없다며 vs.ide가 뜨지 않는다.
-> http://support.microsoft.com/default.aspx?scid=kb;ko;306905
-> regsvr32 "C:\Program Files\Common Files\Microsoft Shared\MSEnv\DTE.OLB"

make me feel free plz

fin.

June 16, 2005

형변환(type conversion)에 대한 짧은 고찰

 형변환

 warning C4267: '인수' : 'size_t'에서 'unsigned int'(으)로 변환하면서 데이터가 손실될 수 있습니다.

 하기 싫어도 프로그래밍하다보면 어쩔수 없이 마주치게 되는, 수 많은 라이브러리와 상용 제품에도 난무하는 형변환 경고 메세지는 너무 흔해서 모두들 아무렇지 않게 생각한다. 형변환에 대한 이상적인 결론을 말하자면 절대로 허용하면 안된다. 이유를 말하자면 간단하다. 결과를 예측할 수 없기 때문이다. 물론 어디까지나 이상적인 결론이다. 이러한 형변환은 여러가지 이유로 인하여, 이것을 피할수 없다. (스크립트 언어 제외) 완벽한 해결책은 단하나다. 모든 숫자형을 범위가 가장 큰 signed 정수형을 사용하면 된다. (스크립트 언어에서는 정수형을 하나밖에 쓰지 않기때문에 이 문제가 없다.)

 프로그래머는 최대한 공간적, 시간적 최적화를 위해 항상 노력한다. 형변환 문제를 겪는 이유중 하나는 바로 프로그래머가 공간적 최적화를 수행하기 때문이다. 일부 프로그래머는 이러한 최적화를 즐긴다. 또 일부 프로그래머는 처음부터 프로그래밍에 입문할때부터 이러한 프로그래머적인 최적화 성향을 지니기 때문에 즐기지 않아도 자연스럽게 이러한 최적화를 수행한다. 조급한 최적화의 문제일 수도 있다. (Premature Optimization) 공간적 최적화의 이점을 얻는 대신 형변환의 불안정성의 단점이 생긴다면, 공간적 최적화를 포기해야 하는게 아닌가 싶다. (cf. 공간적 최적화가 시간적=퍼포먼스에도 이점을 주기도 한다.) 왜냐하면, 일부 특수한 프로그래밍 영역(리얼타임, 게임)을 제외하면 공간적 최적화는 전체적인 퍼포먼스에 비해 얻는 이득이 미미하기 때문이다.

 C/C++ 커뮤니티에서 형변환 문제를 겪는 이유중 또 다른 하나는 이는 기존의 C/C++ 라이브러리가 singed, unsigned 를 혼용해서 사용하였기 때문이다. 대표적인 예를 생각하자면 size_t(unsinged)가 있다. size_t를 사용하다가 일반적인 숫자형과 혼용해서 써야 하는 일이 백만번-_-생긴다. 이 때문에 예외없이 C/C++프로그램에서 (int) (size_t) 캐스팅이 수십개에서 수천개씩 생긴다.

 직접적인 원인으로 생각되는 또 다른 하나는, 프로그래머가 한가지 변수를 두가지 용도를 사용하기 때문이다. 어떻게 보면 공간적 최적화다. 흔한 예제는 어떤 결과 숫자를 리턴하는 경우다. (eg. ::Socket() ) 그런데 함수가 실패했을경우도 하나의 숫자만 리턴하되 그 숫자가 원래 숫자의 범위에서 벗어나는 수중 하나를 에러코드로 사용하게 디자인한다. 이 경우 실은 함수의 성공유무, 값 이렇게 리턴값이 2개지만 두개의 값을 합쳐서 하나의 숫자를 리턴하게 한 것이다. 애초부터 초기의 언어 디자인이, cpu의 디자인이 입력은 여러개 받고 결과는 하나를 반환하도록 되어 있다. 그런데, 함수를 디자인하다보면 이렇게 결과값을 2개 이상 보내야할 경우가 생기는데 대부분의 프로그래머는 이럴때 변수 한개를 사용한다. 왜냐하면, 나의 경우는, 표준 라이브러리가 그렇게 하기 때문에 처음 프로그래밍을 배울때 따라 배웠고, 지금도 그렇게 사용한다.

 글쎄, 무엇이 문제일까? 현실과 타협하고 묵시적변환(implicit conversion) 모두 지시적변환(explicit conversion)으로 바꿔서 컴파일러를 행복하게 해줘야 하나? (라고 썼지만 이미 지금까지 계속 이렇게 컴파일러를 행복하게 해주며 살았다.)

 아직까지 이 문제에 대한 해답을 못찼았다. 대부분의 경우 직접 형변환 하면 문제가 없지만, 가끔 발생할 에러를 미리 방지해야 하는것이 아닌가.

 일반적인 type conversion의 경우 크기가 작은 변수(ex. short)를 크기가 큰 변수(int)에 대입하면 100% 안전하다. 하지만 반대의 경우 일률적인 확률적으로만 계산한다면 그 크기의 차이의 자승만큼 불안정한 확률이 생긴다. (32bit변수를 16bit변수에 대입한다면 (2^16)-1/2^16의 확률) 물론, 일반적인 이러한 형변환은 프로그래머가 제정신으로 형변환하면 10%이상의 실패율을 보일 것이다. signed/unsigned 형변환은 일률적인 확률은 50%, 그러나 제정신인 프로그래머가 형변환하는 것이라면 거의 0.01%이만의 실패율을 보일 것이다. 하지만 아쉽게도 100% 안전하다고 할수가 없다.

//
// check_data_loss_cast<type>(), if casting lose any data it will assert
// long long형의 signed, unsigned 변환시 값이 달라지는 것은 체크 불가능
//
template < typename DST_T, typename SRC_T >
inline
DST_T check_data_loss_cast( const SRC_T& src )
{
 DST_T conv_v = (DST_T)src;
 COMPAT_ASSERT( ((long long)conv_v) == (long long)src, "check_data_loss_cast failed." );
 return conv_v;
}

 데이터 변환시 데이터 소실, 값이 의도치 않게 변경되면 안될 경우에 (사실 항상 이렇게 되면 안된다는 것은 누구나 알고 있다) 데이터 소실시 assert해주는 체크정도는 해야 한다. 아니면, 나중에 뭔가 이상한 데이터가 인자로 들어와서 실패하는 경우를 언젠가는 겪게 될 것이다. 아주 희귀한 경우라면, 이러한 assert가 빠진 릴리즈 모드에서 bug가 발생하겠지만 테스트시에 나는 버그정도는 미리 체크할 수 있을 것이다. (요즘에는 assert를 릴리즈상태에서도 집어넣어 출시하는 경우가 자주 있는듯 하다.)  뭐, 이러한 체크가 가장 단순한 잘못된 형변환에 대한 최소한의 대비책 정도는 될 수 있을 것이다.

"피할수 없다면, 원인을 인지하고 부작용에 대해 대비하라."

June 01, 2005

온라인 게임에서의 캐릭터 이름

 아무리 생각해봐도, 캐릭터 이름 설정을 플레이어에게 맡기는 것은 전체적인 게임의 분위기를 망쳐버린다. 처음부터 이름까지 게임에서 정해주면 어떨까? 캐릭터 설정을 다 하고 난 후에, 혹은 캐릭터 설정까지도 자동으로?

#1 - 현실성 20%

 게임을 접속한다. 캐릭터가 없다면, 캐릭터 설정창 대신에 "게임을 새로 시작한다" 라는 메뉴가 나온다. 클릭을 하면, 종족과 성별을 고른다. "게임 시작" 버튼만 남았다. 클릭하면 화면이 바뀌면서 어느 이름 모를 마을에서 깨어나게된다. 의성표현을 제외하고는 모든 글자들은 낯설다. 무슨 소리인지 알수가 없다. 튜토리얼을 시작하는 초기에는 NPC가 하는 말도 못알아 듣고, 당신의 이름도 모른다. 알수 있는 것이라고는 "당신 앞에 보이는 사람이 (모습을 보면 나이가 지긋히 많아 보이고 걱정 스러온 표정으로 당신을 쳐다보고 있다) 옆에 있는 종이를 가르킵니다. 그 사람이 "매너래ㅑ벚매ㅑㅗ패ㅑ몾ㄹ"라고 말합니다.


 튜토리얼을 끝낼쯔음에 드디어 말과 화면의 글자가 제대로 보인다. 당신의 이름은 "주먹쥐고 후려쳐"다. 게임을 꾀 진행하면서 당신의 성격과 적성을 파악하고 있다. 내 캐릭터는 성격이 불같다. 성향이 악을 띤 npc주변에 가까이가면 (10미터이내) 버서크상태(공격속도 1.5배 향상)가 되면서 자동으로 돌진을 하게 된다. -_-;


#2 - 현실성 50%

 캐릭터를 만들면 성과 이름이 스스로 지어지고 이것은 아명(兒名)이 된다. 다른 사람들도 당신의 정보를 확인하면 그것이 아명이라는 것을 알게 된다. 게임을 하면서 일정레벨 혹은 일정한 기간까지 원하는 이름으로 성인신고(이름 등록을 하게 한다.)를 한다. 이 이름을 인증받게 된다면 이 이름이 본명으로 등록된다. 캐릭터 정보를 보면 본명으로 나오고 이전의 아명도 확인할 수 있다. 이 과정이 귀찮으면 이름 등록을 처음부터 게임에서 주어진것으로 하던가, 이름을 게임에서 주어지는 것들 중 고를수 있다.

 게임을 시작하면 "리처드 게리엇"이란 이름을 받고 성인신고를 "세바스챤"으로 하고 인증을 받는다면 본명으로 "세바스챤 게리엇" 으로 나오게 된다. 캐릭터 정보를 보면 아명인 리처드를 확인할 수 있다. 만약 인증을 받지 않으면 그냥 본명도 "리처드 게리엇"으로 고정된다.

 아는 사람들끼리라면, 그 사람의 게임초대메일을 받고(시스템적으로 출생신고 등으로 표현) 게임을 시작하면 성을 같은걸로 사용할수 있다던지 하는 시스템.

#3 - 현실성 1%

 뭐, 어디까지나 현실성이 떨어지는 예지만 이런건 어떨까, 일단 플레이어가 이름을 맘대로 짓게 한듯 하지만 실제로 다른 사람들에게 보이는 이름은 게임에서 정한다. 실제로 다른 사람에게는 "주먹지고 후려쳐"로 보인다. 하지만 난 캐릭터 이름을 "♡깨어보니형부☆"로 지었다. 다른사람이 날 가르키는 말을 클라이언트에서 필터링하여 날 가르키는 말을 "♡깨어보니형부☆"로 바꿔준다. -_- 물론, 필터링 한다 라는 것 자체가 문자 인식이나 음성인식같이 사람은 알아 듣는데 컴퓨터는 인식을 제대로 못한다는건 알지만 어디까지나 예다. -_- 뭐 게임 설정상 서로 대화가 안되는 상대라면 이렇게 해도 별 무리는 없나 싶다. (와우에서 얼라와 호드의 관계) 와우 같은 게임은 오프라인에서 서로 연락 못하게 하는게 훨씬더 괜찮을 수도 있다. !-_-

ps
 갑자기 생각나서 현실성이 부족한 잡담를 해봤다. (라고 잡소리라고 했지만 스스로는 이렇게 해보면 재밌지 않을까 라고 생각하고 있다. !-_-) 사실, 라이트 게임으로써는 감당하기 힘든 일이다.

May 30, 2005

poor information about cpu

32bit

intel
셀러론 노스우드 = L1 8K, L2=128K, FSB400
셀러론D 프레스캇 = L1 16K, L2=256K, FSB533
P4 노스우드A = L2 512, FSB 400
P4 노스우드B = L2 512, FSB 533
P4 노스우드C = L2 512, FSB 800, HT
P4 프레스캇A = L2 1024, FSB 533
P4 프레스캇E = L2 1024, FSB 800, HT 
P4 프레스캇 5xx = 16K:1M:FSB 800, HT
P4 프레스캇 6xx = 16K:2M:FSB 800, HT
(비지니스 서버용 모델)
제온 = L1 8K, L2 512K, L3 1M, FSB 533 (사양마다 다름, L3없는것도 있음)
제온 노코나 = L1 8K, L2 1M, FSB 800

amd
셈프론 써러브레드B = L2 256K, FSB 333
셈프론 파리 = L2 256K, FSB800
셈프론 팔레르모 = L2 128K, FSB800
애슬론XP 바톤 = L2 512K, FSB333

64 bit
intel
제온 어원데일 = 8K*2M,FSB800 64bit

amd
애슬론64 뉴캐슬 = 128K, 512K, FSB1G

 더 적다가 포기 ┓-

 그동안 하드웨어에 관심 끊은 사이에 무슨 코드명이 이리 많이 나왔단 말이냐...-_-; 암튼 비싼게 좋은거다. -_-;

 일차적인 L1캐쉬비교나 L2캐쉬비교가 의미 없는 이유는 intel과 amd가 각자가 잘 연구해서 최적의 성능을 내게 만든것이기 때문이다. amd는 후발주자였기때문에 무리를 해서라도 L1캐쉬의 크기를 늘려 스펙상으로 인텔을 앞지르려고 한것고, (결과로 더 빠르건 아니건간에-왜냐하면 L1캐쉬의 크키가 커진다면 L1캐쉬에서 캐쉬히트률은 높아지겠지만 커지면 접근속도는 조금느려진다.) 인텔은 기존의 아키텍쳐에 L1캐쉬의 크기를 늘리는게 크게 속도의 이득이 없다고 (테스트의 결과에 의해) 판단했기때문에 비지니스 서버에서 사용하는 64비트 120만원짜리 CPU에도 L1이 아직도 8K로 남아 있는 이유다.

 사용자의 입장에서 보면, 여러 회사가 경쟁하면 좋은 제품을 더 싸게 얻을수 있으므로 이미 크게 이득을 봤으니 뭐... 특정 시기에 컴퓨터를 구입하려할때 그냥 가격대 성능이 뛰어난 걸로 판단이 난 것을 구입하면 문제 없다.

 원래 셀러론과 펜티엄3(지금은4)의 차이가 원래 l2캐쉬크기와 멀티프로세서 시슷템구성여부 였는데 지금은 좀 다른거 같다. 펜티엄3라 붙은 제품은 전부 멀티프로세스시스템 구성이 가능했던 걸로 아는데. 암튼 :D

May 24, 2005

C++ Library Extentions; TR1

TR1 = The Technical Report On C++ Library Extensions

 이름만 가지고는 뭔지 잘 감이 오지 않을 수도 있다. 이것은 practical problem을 해결하는것을 도와주기 위해 WG21(C++ Standardization Committee's Library Working Group)에서 차세대 C++표준(C++0x)이 나오기전에 나름대로의  예비 C++표준라이브러리로써 발표하는 라이브러리이다. (아마도) 대부분의 내용들이 실제 C++0x 표준 라이브러리에 포함될 것이다. 생각하기 쉽게 표현하자면, 지금의 C++을 3.0으로 비유한다면, 3.1 정도의 개념으로 라이브러리만 업데이트했다고 보면 된다.

tr1? 실제 코드에 어떻게 적용이 되는가?

 C++표준 라이브러리는, namespace std에 포함된다. 그리고 tr1은 std::tr1의 이름을 가진다. 차세대 c++표준이 발표된다할지라도 tr1의 내용은 그대로 남기 때문에 이식성 문제는 이것 으로 해결할 수 있고, tr1의 내용의 일부 혹은 대수가 namespace std에 귀속될 것이다. 그리고 tr1이 현재 발표되었고, c++0x의 스케쥴과 관계없이 지금부터 tr2에 대한 논의가 이뤄지고 (만약 c++0x가 생각보다 빨리 발표되게 된다면 tr2의 작업은 c++0x에 녹고 다시 tr2가 시작되서 늦어지게 될 것이겠지만 :D) 수년이 지나면 tr2가 나오게 될것이고, 그곳은 std:tr2의 네임스페이스를 가지게 될 것이다.

예제

 이미 boost라이브러리나 기타 라이브러리를를 통해 수많은 c++ cutting-edge library 개발자들이 c++라이브러리로써 재미있는 기능들을 추가하고 있는데 tr1에 추가되는 것중 하나는 tuple이다. 예제로써 구경하자.


#include <tr1/tuple>
#include <string>

using namespace std;
using namespace std::tr1;
...
tuple<int, char, string> t = make_tuple(1, 'a', "xyz");
// sample 2
tuple<int, int, int> tmp = foo();
int x = get<0>(tmp);
int y = get<1>(tmp);
int z = get<2>(tmp);
// sample 3
tie(x, y, z) = foo();

스크립트 언어에서 여러 변수를 리턴하는 기능을 템플릿으로 구현 한것이다.

다음의 코드는,


const string str =
"a few words on regular expressions";
const regex pat("[a-zA-Z]+");

sregex_token_iterator first(str.begin(),
str.end(), pat);
sregex_token_iterator last;

vector<string> words(first, last);

정규 표현도 tr1에 포함되게 된다.

언제 사용할 수 있는가?

 현재, TR1의 스펙이 발표된 것이지 작동하는 라이브러리가 발표된 것은 아니다. 알려진 바로는,

  • Metrowerks CodeWarrior 9.0 ships with a partial implementation of TR1, including such classes as function, shared_ptr, and tuple.
  • Many parts of TR1, including the smart pointers, regular expressions, and random number generators, were originally Boost libraries (http://www.boost.org/). Boost releases are available, and free, for all popular compilers and platforms.
  • Dinkumware is in the process of implementing the entire technical report. It is the only company I know of that's currently working on the TR1 special functions, like cyl_bessel_j and riemann_zeta, with the goal of achieving accuracy comparable to today's best implementations of functions like sin and cos.
  • The GNU libstdc++ project, which writes the C++ library that ships with GCC, is actively working on implementing TR1. The next release of GCC, GCC 4.0, will ship with a partial implementation of TR1—exactly how partial is hard to say, since TR1 components are being added to libstdc++ on a daily basis.
  • 현실적인 적용

     많은 부분이 나의 사랑-_-을 독차지하고 있는 boost library에서 이미 구현된 기능들이기 때문에, 미리 맛보기를 하고 싶다면 boost library를 사용하는 것이 현명하다. 점유율이 낮은 컴파일러 개발회사의 제품들에 TR1이 추가되고 있는 듯하고(코드워리어, 디쿰웨어라이브러리), GNUC++에 다음버전에 일부가 추가될 예정이니 이를 기다리는 것도 좋을 것이다. 물론, VC72나 VC8에서 기대할 생각은 하지않는게 좋다. VC71에서 표준라이브러리로 Dinkumware 라이브러리를 사다 쓰고 있는 걸로 아는데, Dinkumware에서 추가하고 있다는 소리는 VC에 구현되려면 Dinkumware에서 완전히 구현된후 2년후에나 -_-구현된 다는 소리다. 뭐, 요즘은 VC컴파일러에 비교적 관심을 많이 가져주는 듯해서 (기대도 안했던 C++98표준을 거의다 구현해준-_-) 뭐, 빠릿빠릿 적용해줄지도 모르지만, :D

    레퍼런스:
    http://www.open-std.org/jtc1/sc22/wg21/
    http://www.cuj.com/documents/s=9724/ddj0506h/
    http://open-std.org/jtc1/sc22/wg21/docs/library_technical_report.html



    May 20, 2005

    조엘 온 소프트웨어(Joel On Software)

    찬사가 붙는 책에는 그럴만한 이유가 있다.

    Jolt상을 받는 책에는 그럴만한 이유가 있다.

    프로그래머인가? 관리자인가? 한 회사의 CEO인가?

    그렇다면, 지금 당장, 서점으로 뛰어가든지, 온라인사이트를 가던지,

    조엘 온 소프트웨어를 사라. 번역판의 번역도 괜찮다.

    절대 후회하지 않을 것이다.

    물론 책을 끝까지 읽어야 한다. 조엘씨가 정말로 자신이 알고 있는 많은 것들을 내놓은 듯하다.

    나를 알거나 나에게 빌릴만한 근거리에 있는 분에게는 빌려드릴 의사도 있다. 물론, 지금 대기 순위가 몇명있기 때문에 한달은 지나야 빌려줄 수 있을 꺼 같다.-_-

    http://www.joelonsoftware.com/

    물론, 저자에게나 역자에게나 "그건 아닌데...-_-"라고 말해주고 싶은 부분이 몇군데 있었으나, 전체적인 내용의 가치를 따진다면 그 정도는 이 책의 가치에 흠집도 안 남길만큼 미미하다.

    May 18, 2005

    부스트 라이브러리 빌드하기(how to build boost library)

    서론:

     c++ 프로그래머들의 금기 영역에 자리잡고 있는 라이브러리가 하나 있으니 그 이름은 'boost' 라이브러리다. "강철의 연금술사"의 내용을 빌자면 일종의 프로그래밍 영역의 "인체연성"이다. 좋게 말하자면, 액션 게임에서 흔히 보는 자기 에너지를 닳게 하고 사용하는 무적 필살기이지만, 나쁘게 말하면 악마에게 자신의 영혼을 팔아 원하는 바를 이루지만 과연 이것이 자신이 원하던 결과였는지 곰곰히 생각해보게되는, 그런 것이다.

     물론 모든 프로그래머에게 이런 룰이 적용되지는 않을 것이다. boost라이브러리를 좋아하는 사람들을 정말 좋아하지만, 싫어하는 사람들은 쌍욕까지 나오게 하는 금단의 라이브러리. 나에게 있어서는 boost라이브러리는 하나의 대단히 훌륭한 레퍼런스이지만 내게 라이브러리로써 쓰고 싶은 마음이 들게 하지는 않는 물건이다. -_-;

     물론 안좋은 추억이 있기는 하지만, boost library의 가장 큰 문제점은 너무나 많은 사람들이 달려들어 자신의 멋진(?) 코드들을 라이브러리안에 추가시켰다는 점이다. 세계 만국의 미인들의 눈,코,입,얼굴 부위, 부위를 떼어다가 붙인격이다. 그래서 코드 스타일의 변동도 많고 정말로 ugly한 각종 macro도 들어가있고 서로서로 무지하게 커플링되어 있어서 소스가 공개되어 있지만 그걸 직접 보기란 -_-;

     개인적인 안좋은 추억으로는 예전에 내가 쓰려는 라이브러리가 boost라이브러리를 사용하기 때문에 boost라이브러리를 사용하려했으나, boost와 stlport의 환상적인 싱크로율 170% 콤보 어택으로 10시간 가량을 허비한 경험이 있다. 결국 stlport를 배려하려 했던 regex쪽 코드를 수정해서 해결했던것 같다. 뭐 이런 시시한 이유로 난 boost library를 라이브러리로써 싫어하고 앞으로의 프로젝트에 boost를 포함할 계획을 없다. (물론, 필요하다면 부분부분 직접 힘든 과정이겠지만 떼어내어서 사용할 생각은 있다.)

     그럼에도 불구하고, boost 라이브러리는 온갖 c++/template/macro를 이용한 실험적이고 천재적인 아이디어와 interface들이 산재해있기 때문에 시간이 많이 걸릴지라도 boost library를 보는것은 프로그래머로써 시간대성능비로써 훌륭하고 여러가지 앞으로 라이브러리/인터페이스 설계나 template 프로그래밍, 매크로[#define](를 지양해야 하지만 필요한 경우가 있으므로) 프로그래밍에 관한 깨닮음과 통찰력(이라고 하면 좀 오바일지도 모르겠지만)을 얻을 수 있다. 그리고 boost라이브러리의 개발자들이 C++표준라이브러리위원회[C++ Standards Committee Library Working Group]의 멤버들로 시작하였기 때문에, 여기에 들어간 라이브러리는 차세대 C++ 표준 라이브러리에 들어갈수도 있다. :D

     서론이 너무 길었다-_- 워낙 평소에 boost library에 대한 악감+호감이 많아서, 이 글은 boost library를 오랫만에 컴파일하면서 쓰는 글이다.

    Continue reading "부스트 라이브러리 빌드하기(how to build boost library)" »

    C/C++ Users Journal, 2005/05 Issue

    The Design of C++0x

    Bjarne Stroustrup
    If you were the ISO C++ Standards committee and could decree what the next C++ Standard looks like, what would you add? What would you remove? What would you change?

    C++ Function Objects in TR1

    Pete Becker
    The Technical Report on C++ Library Extensions (TR1) introduces four new function object templates that use more sophisticated implementation techniques than the function object templates in the C++ Standard Library.

    * 간만에 비사마아저씨가 아티클을 올렸군요. 이전에 알고 있던 내용과 다른게 있는지 체크해보겠습니다. 아직 읽기전.

    --- 더 보려면 자세히 보기 ---

    Continue reading "C/C++ Users Journal, 2005/05 Issue" »

    May 10, 2005

    해커가 되는 법

    # 일단, 국내에서 쉽게 말하는 해킹과는 관련 없는 글임을 밝힌다. 쉽게 말하는 해킹이나 조잡한 해킹 프로그램 구하러 왔다면 어서 back 버튼을 누르길 권장한다.

    -_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-

     성당과 시장이란 글[책]으로 유명한 Eric Raymond가 쓴 글이다. 요지는 어떻게 하면 hacker가 되는가에 대한 길잡이, 개론이다. 오픈소스쪽에서 가장 유명한 사람중 한명이기 때문에 너무나 많은 사람들로부터 어떻게 하면 hacker가 되는가에 대한 질문을 꾸준히 받았고, 이러한 글이 없어서 썼다고 한다.

     이 글을 읽고 몇가지 생각이 들었다. 사실 나는 이글에서 말하는 hacker가 되려고 했다. 노력하려고 했고, 지금은 삶에 찌들어 많이 잊고 살아가고 있다고 할까. [가장 최근의 원흉은 뭐니뭐니해도 WoW-_-] 몇가지가 눈에 띄었는데 적어서 정신 차리는데 쓰려 한다.

    # Boredom and drudgery are evil.
     % drudgery: 고역, 단순 노가다

    나는 이 문장을 추가하고 싶어졌다.
    But laziness is root of all evil!
    게으름! oTL 그러나 귀차니즘과는 구별되야 한다. 게으름은 일A가 있는데 3%정도 하다가 말고 "아우 귀찮아"하고 누워 자빠져 쳐 자는것 이라면, 귀차니즘은 일A를 3%하다가 나머지 97%를 같은 방식으로 하는것이 귀찮아서 A를 대체할수 있는 다른 센스있는[혹은 쉬운] 방법B를 찾아내어 완료하는 것 이랄까. 뭐 현재의 나에게는 laziness가 양 다리를 붙잡고 있다는 점은 스스로 화가날정도로 인정하고 있다.

    # If you don't have functional English, learn it.

     Ack!악! 한 2-3달정도 게임만 주로 하고 회사에서 끄작끄작 프로그래밍만 조금 했더니 오랫만에 보는 영어가 나의 눈을 아프게 했다. 반성하자!

    # Learn to write your native language well.

     역시 2-3달 이렇게 살았더니, 한글 오타가 발생하는 것이 장난 아니고 앞뒤 문맥 안맞는 외계어 남발에 글을 점점 더 못 써간다. 한글을 명료하고 정확하게 쓰자! 그러기위해서 여행기를 쓰려 했지만... 어떻게 된걸까-_-;

    # Train in a martial-arts form.

     운동하자. 솔직히 나에게 꾸준한 헬스는 무리고, 검도나 다시 다녀야겠다.

     비록, how to become a hacker 라는 글을 읽었지만 개인적인 전반적인 문제점들을 조목조목 되새길수 있는 계기가 되었다.

    링크: How to Become A Hacker

    ps. 간만에 영어 이만큼 읽었다고 눈이 아프다니-_- 정말 뭔가를 잡고 반성해야겠다.

    ps. 이 사람 블로그를 끄적이다. 링크를 발견해서 읽게되었다.

    April 20, 2005

    packet handler

     network/client-server/p2p programming에서 가장 많은 양의 코딩이 이뤄지는 부분은, 역시 실제 주고 받는 패킷에 대한 처리이다. 일단 들어오는 패킷에 대해서는 command pattern비스무리하게 packet_header to handler_function으로 자동으로 매핑해서 if else의 무리나, switch case를 제거했다. 하지만, 뭔가 packet handling하는 내용은 뭔가 패턴이나 뭔가 좀더 편하게 짤수는 없을까? packet protocol은 일단 binary로 설계하였다.

    int GameClientHandler::Process_Game_Leave_Room( const Message_Header* header, int length )
    {
     ReceiveAssist< Game_Leave_Room_req > r( header, length );

     SendAssist< Game_Leave_Room_rep, REP_GAME_LEAVE_ROOM > s( this );
     s.body->result = T_ERROR_OK;
     s.body->tid = r.body->tid;
     if ( !my_room_->LeaveUser( this ) )
      s.body->result = T_ERROR_GENERAL;
     my_room_ = 0;
     s.Send();
    }

     서버가 늘어난다거나, 무슨 일이 생기면 가장 많은 양의 코드가 바로 이 패킷 처리 핸들러의 추가/변경 인데, 이 일이 발생하면 해당 프로토콜에 맞는 struct역시 추가/변경이 되야하기 때문에! 뭔가 더 좋은 방법이 없을까?

     이 이상의 방법은 없는 것일까-_-;

    April 19, 2005

    64bit 시대의 도래를 위해 프로그래머로써 준비해야 할것

    64bit os의 unsinged integer의 최대값은

    1844경 6744조 737억 955만 1615

    32bit os의 unsigned integer의 최대값은

    42억 9496만 7295

    16bit os의 unsigned integer의 최대값은

    6만 5535

    ---

    singed integer의 최대값은 (x+1)/2-1 하면 된다.

    32bit integer최대값을 까먹었었다. 64bit꺼랑 같이 다시 외워놔야지 -_-;

    뭐 사실 누가 물어봐도 0xffffffffffffffff, 0xffffffff 라고 대답할수는 있지만!

    March 21, 2005

    template usage case #1

    template < typename T >
    class T2
    {
    public:
    // typedef typename T::value_type v_type;    // --- #1
     T2()
     {
      T::value_type a;      // --- #2
      a = 1;
     }
    };

    typedef int t1_value_type;

    class T1 : public T2< T1 >
    {
    public:
     typedef t1_value_type value_type;
     void test() {}
     void test1( value_type ) {}
    };

    void func()
    {
     T1 a;  // --- #3
    }

     #1은 컴파일이 안되지만, #2는 컴파일이 된다. 왜냐하면 #1의 라인은 T1클래스가 Instantiation되기전에 T2클래스가 먼저 Instantiation된다. 따라서 T2클래스 입장에서 T1::value_type이 존재하는지 하지 않는지 알지 못한다. 하지만 #2의 경우는 이야기가 다르다. #2가 Instantiation되는 타이밍(POI=Point of Instantiation)은 #3의 구문을 보고 그제서야 T2의 생성자가 Instantiation되기 때문이다. 이 시점에서는 T1과 T2의 클래스의 타입은 이미 Instantiation되었기 때문이다. template의 강력함(?) 중 하나는 바로 이것이다. 

     멤버함수의 경우 실제로 참조하지 않으면 코드를 생성하지 않는 기능. 용량적으로도 코드크기가 줄어서 좋다.

     예제로 적은 스타일의 방식을 개인적으로 많이 사용한다. 뭐.. 쓰다보니 이 스타일이 왠지 유용하다. 일반적인 슈퍼클래스의 개념은 단순한 일에 치여 돈만 벌어다 주고 자식에게 관심이 없고 아이들이 혼자 스스로 성장하는 아빠의 느낌이랄까! 하지만 이 방식은 슈퍼클래스인 주제(-_-)에 서브클래스를 좌지우지 하는 이를테면 돈도 많이 버는 아빠지만 주말엔 꼭 아이와 놀아준다는 일도최고가정에도최고인 느낌. -_-;

    fin.

    March 08, 2005

    최근에 추가한 템플릿 유틸리티

    #1 YetAnotherStringTokenizer;

    뭐...특별한 커멘트가 필요하지 않을것이다. 인터페이스는 이렇다.

      LPCSTR string_buffer2
       = "killing me softly, \r\nm-flo nice, \r\n xecode  kfc-_-,owo";

      compat::StringTokenizer tokenizer(
       string_buffer2,
       strlen(string_buffer2),
       ",", // deliminator
       "\r\n\t" // spaces
       );

      while( T_LPCSTR tok = tokenizer.Next() )
      {
       Console::Log( "tok[%s]\r\n", tok );
      }

    #2 template function, SafetyExecution

    일단, 이름이 수상할 것이다. -_-; 실제 하는 행동도 수상하다. -_- 요는 이렇다. 잠재적으로 잘못된 연산을 수행할 위험요소가 있거나 믿을수 없다거나 (보안상의 의미가 아님)  하는 코드의 부분을 프로그램 비정상 종료의 위험없이 실행해주는 템플릿 함수다. 물론 win32 structured exception mechanism이 사용되었다. 그리고 당연한거지만 win32플랫폼이 아니면 일반 호출과 다를바 없다. 대략적인 최종적으로 고안된 인터페이스는 다음과 같다.

    void* safety_execution_1_func( int a1, float a2 )
    {
       int* p = 0; *p = 0; // runtime error
     return (void*)100;
    }
    DECLARE_FUNCTOR_2( safety_execution_1, safety_execution_1_func, int, float, void* );

    bool safety_execution_2_func( )
    {
       int* p = 0; *p = 0; // runtime error
     return true;
    }
    DECLARE_FUNCTOR_0( safety_execution_2, safety_execution_2_func, bool );

    class safety_execution_3_helper
    {
    public:
     int safety_execution_3( LPCSTR data, int size )
     {
      int i = 100;
      int d = 0;

        i /= d; // 0으로 나눔
      return 0;
     }
    };
      void* ret_1 =
       compat::SafetyExecution(
        0,  // failed return value
        safety_execution_1(),
        50,   // arg1
        100.0f ); // arg2

      bool ret_2 =
       compat::SafetyExecution(
        false,  // failed return value
        safety_execution_2() );

      safety_execution_3_helper se3_h;

      int ret_3 =
       compat::SafetyExecution(
        -1, // 비정상오류를 캐취했을시 리턴값
        compat::mem_fun2( safety_execution_3_helper::safety_execution_3 ),
        &se3_h,      // class pointer
        "safety_execution_3 test", // arg 1
        100 );      // arg 2

    물론 오류가 났을시, callstack도 프린트 해준다. (msdn bugslayer 참조)

    역시 프로그래밍관련 이야기가 아니면 딱히 쓸 이야기가 없구나!-_-

    ps 글을 쓰고보니 , #1은 그냥 클래스군요!!

    December 27, 2004

    template을 이용한 sync coding: [수정]

     최근 sync/thread 베이스 라이브러리를 연구/개발-_ -중이다. 그래서 최대한 이쁘고 깔끔하고 효율적인 코딩을 하려고 노력중이다. 뭔가 wierd한 클래스 디자인이 되어 간단히 소개(?) 하기로 한다.

     최초의 디자인은, mutex, spinlock, recursivemutex등 몇가지 기본적인 sync object에 대해 c-style 플랫폼 의존적이지 않은 api wrapper를 제공하고 이를 이용하여 class화 시키는 것이었다. 그런데, 일단 기본적으로 mutex를 c-style api화시키고나서 이를 class로 만들고 난후 잠시 든 생각은 몇가지 sync object의 인터페이스가 template의 관점으로 볼때 정확히 일치한다는 점이다. 그래서 템플릿으로 좀더 이쁘게 짜기위해 잠시 생각을 해보았다.

     예를 들면, 이런 인터페이스면 이쁘다고 생각했다.

    TLock< SpinlockMetatype > lock;
    TLock< MutexMetatype > lock2;

    lock.Init();
    {
     lock.Acquire();
    // access my thread-sensitive object
     lock.Release();
    }

    (물론 실제로는 "Scoped Locking" DP를 이용해서 직접 release를 호출하지는 않을 생각이다.)

     그래서 처음에는 암생각없이 TLock이라는 결과적으로 내가 원하는 최종 템플릿클래스의 파라메타로 "struct로만든 metatype"을 만들어 이를 넘길 생각이었다. 하지만 함수포인터를 넘겨받아야 하므로, struct말고 class로 만들어 생성자를 이용하여 직접 함수의 포인터를 초기화하여 이를 TLock안에서 인스턴스화하여 c-style api에 접근하기로 하였다.

    그래서 만들어진것이,

    // 메타타입 클래스
    template < typename LOCK_HANDLE_TYPE >
    class TLockMovableType;

    // 팩토리 함수
    TLockMovableType<MY_HANDLE_TYPE> TLockMovableType::Make();

    // 원하는 generic TLock 템플릿 클래스
    template < typename LOCK_MOVABLETYPE >
    class TLock;

    // 생성자는
     TLock::TLock() :
      mt_(0,0,0,0,0)
     {
      mt_ = typename LOCK_MOVABLETYPE::Make<LOCK_HANDLE>();
     }

    // 사용하는 법은,
    typedef TLockMovableType< MutexHandle > MutexMetatype;
    TLock< MutexMetatype > myLock; myLock.Init();

    // "Scoped Locking" DP를 적용한 예제는
    typedef TLockMovableType< MutexHandle > MutexMetatype;
    TLock< MutexMetatype > myLock;

    {
      // Scoped가 들날날락할때 일을 하는 generic-_ -홀더 클래스.
      ScopedOperationHolder holder( MakeLockingOp(myLock) );
      printf(">>>> accessing my thread-sensitive object\r\n" );
    } // myLock.Release() 가 holder의 파괴자에의해 묵시적으로 호출

    // 보완점.
     처음부터 c-style api를 제공하려고 했기 때문에 실제로 이런식으로 사용하게 되면 컴파일러가 c-style api를 최적화 할지 안할지 모르겠지만 일단은 안한다고 보면 된다. 왜냐하면 메타타입안에 c-style api의 함수의 포인터가 들어가기 때문이다. 이에 대해 컴파일러가 inline 최적화를 하게 도와주려면, c++의 functor개념을 이용하면 되는데, 처음부터 c-style api를 제공하려생각했기 때문에, 모든 함수에 functor를 사용하려면, 직접 함수마다 하나씩 생성해야 하는 딜레마에 빠진다. 물론 define을 이용하여 조금 편하게 만들수는 있긴 하지만.............-_ -;

    ps 너무 학술적인 포스팅인가!-_-;

    ps수정:

    결국 고민하여 만든 조금 긴 템플릿 클래스는 인라인이 안되는 함수포인터를 제거하고, 걍 간단한 매크로를 정의하여-_ -(사실 매크로는 피하고 싶었다.) 문제를 해결했다. 사용하는 코드는 정확하게 같고 backend만 고쳤다.

    정의한 macro는 딱 두개.


    #define DECLARE_UNARY_FUNCTOR( FUNCTOR_NAME, API_NAME, PARAM_TYPE1, RETURN_TYPE )    \
     struct FUNCTOR_NAME                   \
     {                       \
      RETURN_TYPE operator () ( PARAM_TYPE1 arg1 )           \
      {                      \
       return API_NAME( arg1 );               \
      }                      \
     }

    #define DECLARE_BINARY_FUNCTOR( FUNCTOR_NAME, API_NAME, PARAM_TYPE1, PARAM_TYPE2, RETURN_TYPE ) \
     struct FUNCTOR_NAME                   \
     {                       \
      RETURN_TYPE operator () ( PARAM_TYPE1 arg1, PARAM_TYPE2 arg2 )       \
      {                      \
       return API_NAME( arg1, arg2 );              \
      }                      \
     }

    원래 의도하던대로의 메타타입 "struct"
    struct MutexMetaType
    {
     typedef os::MutexHandle LOCK_HANDLE;

     DECLARE_BINARY_FUNCTOR( Lock_Init, compat::os::Mutex_Init, LOCK_HANDLE&, void*, bool );
     DECLARE_UNARY_FUNCTOR( Lock_Fini, compat::os::Mutex_Destroy, LOCK_HANDLE&, bool );
     DECLARE_UNARY_FUNCTOR( Lock_Acquire, compat::os::Mutex_Lock, LOCK_HANDLE&, void );
     DECLARE_UNARY_FUNCTOR( Lock_Release, compat::os::Mutex_Unlock, LOCK_HANDLE&, void );
     DECLARE_BINARY_FUNCTOR( Lock_TryAcquire, compat::os::Mutex_TryAcquire, LOCK_HANDLE&, TimeValue, bool );
    };

    끝.

    December 20, 2004

    ms visual studio roadmap 2004-2005

    http://msdn.microsoft.com/vstudio/productinfo/roadmap.aspx

    Figure 1. Developer Tools Roadmap

    ---

    어찌나 vb에 애정을 갖고 있는지 vb에 여러가지 편한 기능들을 추가하는군요 :) vc++쪽은 .net 2003에서 이미 표준에 준하는 기능을 모두 지원해서 그런지, managed c++쪽 기능만 잔뜩 추가될 예정이고, stl 새버전을 사용한다는 것 외에는... sql server는 2000에서 2005으로 대폭 업그레이드?

     orcas는 longhorn과 발맞춰 나올예정이라는 차차세대 개발툴의 코드이구요, 심심해서 포스팅했습니다. :)

    http://blogs.msdn.com/cyrusn/archive/2004/11/08/254266.aspx#FeedBack

     ms에서 blog툴을 만들어 직원들끼리 사용중이고 이를 외부로 보라고 만든곳입니다. 그런데, 이쪽까지 스팸으로 얼룩져있군요. 스팸은 피할 수 없는 것 일까요...-_ -; 한글로 된 스팸이 다행이도 blog쪽에 적어서 좀 들 쪽팔리네요 요즘은, 전에는 유명한 배포판 메일링리스트에 한글로 된 스팸메일이 얼굴을 화끈하게 만들었는데 :)

     이곳에 유명한 몇몇 ms개발자들의 블로그도 있는데, 거의 사용을 안하더군요 :) 여러가지 ms직원들이 쓴거라 재미있는 아티클도 눈에 띄구요.

    December 15, 2004

    the script language, Lua

     내가 너무 이놈을 과소평가했나, -_ -;

     현재 lua는 버전이 5.x대다. 그렇다고는 해도 이전까지 내가 Lua에 대해 갖고 있던 생각은 "그저, 흔하고 흔한 기능이 좀 떨어지는 게임에 스크립트엔진으로 자주 쓰이는 언어" 이었다. 이것은 몇일전에 다운로드 받았을때 소스파일형태로 제공되고, msvc 프로젝트 파일도 제공되지 않고 그냥 "install" 문서파일에 이러이러한 파일들을 묶어서 라이브러리를 만들고 링크해서 인터프리터와 컴파일러를 만들라고 되어있는 부실하다고 생각할수 있는 것을 본것도 이러한 내 Lua에 대한 배경에 힘을 더해 주었고, 인터프리터만 포함한다면 소스파일도 겨우(?) 주석을 포함하여 25만바이트밖에 되지 않은 나에게 Lua에 대해 과소평가를 하지 않을 수 없게 끔 만들었다.

     그런데, 이 스크립트 언어의 공식 도큐먼트, offline에서 팔릴뿐 아니라, 온라인 형태로 인터넷에서 제공되는, 를 보면서 내 생각은 서서히 바뀌기 시작하였다. 뭐 그래봤자 아직 이 언어에 대해 자세히 알게된게 몇시간도 지나지 않았지만, 너무 막강하고 flexible이 뭔지를 나에게 보여줬다. 물론, 다른 스크립트 언어에서도 대부분 지원하겠지만, 일단 여러가지 의미로 객체 지향 프로그래밍이 가능하고, 너무나 자유자재다. 겨우 주석이 포함된 25만 바이트(line이 아님!)짜리 스크립트언어에서 오퍼레이터 오버로딩이 가능하고, coroutine, 기타 다 설명하기 어려운 많은 부분이 나를 감동시켰다.

     기껏해야 98년쯤 시작한줄알았는데 알게 모르게 93년에 처음 만들어진 언어라니 :) Lua에 대해 Creator가 직접쓴 문서를 읽어보니 Creator가 언어학에 상당히 깊은 조예가 있다는 것도 알게되었다. 저자(들)에 대해 잠깐 뒷조사를 해보니, 브라질의  PUC-Rio 라는 대학의 조교수다. :)

     일단 언어에서 built-in type은 딱 세가지다. number, string, table. 모든 기타 자료구조는 table로 다 구현한다. :) lambda 함수도 지원하고,

        co = coroutine.create( function ()
               print("co", coroutine.yield());
             end);
        coroutine.resume(co);
        coroutine.resume(co, 4, 5);

     coroutine을 이용하고 갖은 이상한 짓들을 다하고, 스크립트라면 당연히 가져야할 것이겠지만, interpret 언어를 오랫만에 사용하다보니 너무 반갑고-_ -지적 유희를 나에게 주기 충분했다.

     the key feature of corutine is their ability to turn upside-down the relationship between caller and callee.

    인상 깊은 구절 & 기능.

    함수내에서 다른함수를 호출할때 일반적으로 컴파일러는, 스택을 현재 함수의 정보를 저장하기위해 지금의 스택을 그대로두고 스택에 필요한 정보를 저장하고 새로훈운 함수에서 일정한 스택을 다시 잡아 사용한다. 일반적으로 무분별한 recursive를 사용할때, 이러한 이유로 stack overflow가 나곤한다. "proper tail calls" 이란, 함수에서 다른 함수를 호출할때, 더이상 현재 함수의 스택을 유지할 필요를 느끼지 못하면 스택을 정리하고 새로운 함수가 그 위치의 스택을 사용하는 것을 의미한다. 예를 들어보면,

    function f(x)
        return f(x+1);
    end;

     위의 함수 f에서 재귀적으로 f(x+1)를 호출할때 사실 현재 함수는 더이상 존재할 필요가 없게된다. 따라서 여기서 proper tail call이 적용된다. 그러므로 이 재귀함수는 적어도 stack overflow는 일어나지 않는다. -_ -; 이러한 기능이 lua에 적용이 되었다고 한다. 갑자기 vc++에서 이러한 최적화가 있는지 궁금해졌다. 하지만 어디에서 관련 정보를 찾아볼수가 없다. 그런데 이렇게 하면 문제가 디버깅을 할때, call_stack을 자주 살펴보는데, 음... 어차피 release에서만 최적화가 일어나면 되는걸까. 잠시 생각해보니 vc++에서 이러한 최적화를 안했을 이유가 없다고 생각된다.

     잡담이 너무 길어졌다. 결론은 "Lua is the one script language for me". 처음에 사실 python을 프로그램에 임베딩해서 사용하려고 했는데, (예전부터 python을 조금 좋아하긴했다. 집에도 무려 오래전에 직접 구입한 책이 한권 존재한다!)  영 embedding관련 api 레퍼런스가 이상해서 포기했다!

    ps. 완전히 횡설수설 Lua에 대한 극찬이 담긴 긴 "잡담"글이 되었다.
    ps. (function () this.body = nil; end)();

    참조URL: 

    사용된 유명한 프로젝트:

    • 발더스게이트
    • 홈월드2
    • 월드 오브 워크래프트

    function should first-class variable?

     c++안에서 임베딩을 하기위해 여러가지 스크립트 랭귀지를 살펴보다 보니, 참 재밌다. lisp이나 python, lua등은 function이라는 것 자체가 대부분 first-class variable이다. 의미는, 변수에 저장되고 함수에 인자로 전달될 수 있다는 것이다. 뭐 정확한 논리적인 의미는 -_ -; 일반적인 언어에서 보통 변수같이 취급된다는 뜻이다. c나 c++에서 함수는 second-class로 표현된다.

     아주 오래전에 stackless-python이라는 재미난 python 클론을 볼때 이상한 희열을 느꼈었는데, 그 후 수 년 c++만 하다가 오랫만에 스크립트 랭귀지의 스펙을 살펴보니 역시 재밌다. python 과 lua중 고민하다가, python이 역사가 오래 됐음에도 불구하고, 변변한 embeding 예제가 존재하지 않아. ("헬로월드"수준의 예제는 존재한다.) lua를 살펴보는데, 이넘은 충분히 직관적이고 소스코드 자체가 매우 가볍워 (언어 자체의 기능도 가볍지만 스크립트언어가 가져야할 모든 장점은 다 가지고 있다.) 적용하기도 쉽고, python의 c API는 뭔가 복잡하고 직관적이지 못한데다가 api 레퍼런스도 설명이 부실해서 그런지 lua는 적용하기 참 쉽다. 아마도 이게 많은 게임에서 python대신에 lua를 스크립트로 쓰는 이유일 것이다.

     참고로, WOW역시 lua+xml로 스크립트를 사용하였다. 일단, 상용으로 성공적으로 쓰인 언어이니, 뭐... 전혀 나중에라도 확장성이나 이상한 일로 인해 다른 언어로 바꿔야 한다던지 하는 일은 없을듯 하다.

    first-class

    lexical scoping

    proper tail calls

    eof

    December 08, 2004

    내부 컴파일러 오류

    ------ 빌드 시작: 프로젝트: Compat, 구성: Debug Win32 ------

    컴파일하고 있습니다.
    compat_script.cpp
    w:\_projectM\DevSample\Compat\script\compat_script.h(36) : fatal error C1001: 내부 컴파일러 오류
            (컴파일러 파일 'msc1.cpp', 줄 2701)
             자세한 내용을 보려면 Visual C++ [도움말] 메뉴에서 [기술 지원] 명령을
             선택하거나 기술 지원 도움말 파일을 참조하십시오.

    빌드 로그가 "file://w:\_projectM\DevSample\Compat\Debug\BuildLog.htm"에 저장되었습니다.
    Compat - 1 오류, 0 경고


    ----------------------완료----------------------

        빌드: 성공 0, 실패 1, 생략 0

    VC7.1에서도 내부 컴파일러 오류 만들기 성공!

    어쩌라고? 왜그래? 앙탈이야? 사랑과 관심이 필요해? 그런거야?-_ -;

    November 29, 2004

    분산 컴파일링 in VC6,7

    참조 URL: http://www.xoreax.com/

     분산 컴파일링을 도와주는, VC++ plugin. 결국, 컴파일러는 input만 제대로 주어준다면야 output에 전혀 문제가 없겠지. 컴파일시간이 한시간씩 걸리는 프로그램을 개발하고, vc를 쓴다면 한번쯤 고려해봐야 할거 같다.

     아님, open source로 이런 툴이나 만들어볼까. 조금 땡기는걸-_ -;

     단, 문제는 소스가 vc에 한정되기 때문에, 그 소스는 다른곳에서는 아무짝에는 쓸모없는 junk 덩어리라는 점-_ -;

     그래도 개인적으로 VC컴파일러는 정말 잘만들었다고 생각한다. 예전에 VC만 쓰다가 C++Builder를 쓴적이 있는데 컴파일속도 때문에 느려서 짜증나 죽을뻔한적이.-_ -; pch(프리컴파일드헤더) 기능이 켜지면 vc컴파일속도의 절반도 못 따라옴. 물론 프로그래머가 pch기능을 염두에 두고 including을 잘못했을수도 있지만 :)

    제작자측의 말을 인용하자면,

    "Slow compilation time has always been one of the C++/C programming language's weakest spots."

    그나저나 배고프다. oTL

    ps WoW, Gnome Wizard, Level 25 Kiku in Dalaran

    ps2. 가마수투라한국의 영등위가 Ghost Reacon 2를 ban했다는 기사가 실렸근영. -_ -;