이상한 코드를 많이 봐야, 노멀한 코드에 감사하게 된다.

 int dogs = 0;
 int cats = (dogs = 17,240);

 printf("%d\n",cats);
 printf("%d\n",dogs);
























-

 int* Js = new int[1004];
 int*  p = Js;
 
 Js[0] = 0;
 Js[1] = 1;
 
 // 접미형 증감, 참조 연산자가, 접두형 증감, 참조 연산자보다 우선순위가 높다. 따라서 포인터 연산이 발생하나
 // x에 대입 되는 값은 포인터 연산에 영향을 받지 않은 값이다.
 int  x = *p++;
  

 printf("%d\n",x);
 printf("%d\n",*p);

 

 delete [] Js;



일반, 템플릿 함수를 템플릿함수포인터 형태의 매개 변수에 넘겨보기

template<class T>
T testFunc(T a[][4])
{
     printf("%d",sizeof(a));

     return 0;
}


template<class T>
void testFunc2(T (*pFunc)(T a[][4]))
{
     T arr[][4] = { {0, 0, 0, 0} };
     pFunc(arr);
}


int testFunc3(int a[][4])
{
    printf("%d",sizeof(a));


    return 0;
}


int _tmain(int argc, _TCHAR* argv[])
{
     // 반환 타입 및 인수 타입이 결정된 형태의 함수는 당연히 되고
     testFunc2(testFunc3);               


    // 템플릿으로 지정된 반환 타입 및 인자가 결정안된 상태의 순수 템플릿 함수는 안되고
     testFunc2(testFunc);         
    
    // 템플릿 문법으로 인자 형식을 전달받은 템플릿 함수포인터를 받는 함수는 순수 템플릿 함수를 수용할 수 있고(헐; 왠지 멋지다)
    testFunc2<int>(testFunc);

    // 템플릿 문법으로 형식으로 전달받은 형식과 인자로 전달되는 형식에 차이가 있으면 안되고
    testFunc2<int>(testFunc<char>);
        

    // 템플릿으로 지정된 반환 타입 및 인자를 결정할 수 있는 정보를 제공 받은 상태의 템플릿 함수는 함수포인터로 전달이 되고
     testFunc2(testFunc<int>);         
   
     return 0;
}

 
-

요점은 템플릿 함수는 인자 혹은 템플릿 문법 으로부터 자신에 대한 형식 정보를 어떻게든 추측할 수 있어야 한다는 것, 2가지다 제공 된다면 두 정보가 같아야 된다는 점.(테스트 환경은 VS2008)


다차원 배열에 대한 메모

값을 배당할때나, 함수로 전달할때나 맨앞 인덱스만 생략이 가능하다.

int a[][2] = {    { 1, 2 }, { 3, 4 } };
되지만
int a[2][] = {    { 1, 2 }, { 3, 4 } };
안된다.

void function( int p_array[][4] )
되고
void function( int p_array[4][] )
안된다

맨앞 인덱스 길이가 유동적일 수 있는 배열을 넘길때에는

void Process( int p_monsters[][3], int p_monstertypes )

이런식으로 맨 앞 인덱스의 값을 따로 넘겨주는 기법을 쓰면 된다.

이책을 읽으며 -


패턴이라는것

// 출현프레임,유닛종류,이동패턴
int Enemy_AppearSchedule_Table[5][3] =
     { 20, 0, 0, 
       20, 0, 1, 
       30, 0, 2, 
       40, 0, 0, 
       50, 0, 1};
이렇게 출현 스케쥴표를 만들어 놓고 패턴은 다음과 같이 정의해볼 수 있다.

//시작x,y 증감치  중간목표위치 증감치 중간목표위치 증감치 종료x,y
int pattern[2][14] =
{ 640, 100,  -6, 0,  220, 100,  0,  10,  220, 200,  -10, 0, -200, 200,
  640, 400, -10, 0,  220, 400,  0, -10,  220, 300,  -10, 0, -200, 300
}

중간에 꼭 거쳐야 하는 지점과, 그 지점 사이의 이동 속도와 방향을 정의해서 지그재그로도 이동도 지정할 수 있다.
패턴 정의를 링크드 리스트 등으로 구현하면 조금 더 유연하게 이동을 디자인할 수 있겠다는 생각이 든다. 다만 링크드 리스트를 사용하면 자료를 처음에 초기화할때 고정된 테이블을 사용하는 것 보다 복잡하게 로딩해야 할 것 같다.

이책을 읽으며 -

정말 부정확한 메모 경로 찾기 - A*

2차원 맵구조에서 지점에서 지점으로의 경로를 추출하는 방법에는 일단 초보적인 너비우선탐색법 이라는 것이 있다. 이 방식은 시작점에서 떨어진 수준 순서로 처리가 된다. 여기서 처리라 함은 간단히 자기 주변 노드들을 처리 대상 모음 힙에 넣는 일이다. 넣을때 중요한 일이 하나 있는데, 넣어지는 녀석의 데이터 구조에 자신을 넣은 노드를 지목하는 란에 현재 처리 대상 노드를 넣어서 힙에 넣는다.
 
이 방법은 너무 제약과 단점이 많기 때문에 게임 에서는 주로 다른 방식을 사용하는데 거리우선탐색법 이라는 구조다. 너비우선탐색법에서는 대각선에 놓인 노드와 수평으로 옆에 놓인 노드가 같은 실행 순서를 할당받을 수 있었다면, 거리우선탐색 구조에서는 대각선은 수평,수직 부분 처리가 모두 이루어진 후에 이루어지게 된다.

거리우선탐색법을 응용한 여러 방식이 있는데 그 중에서 가장 유명한 것이 A*(에이스타)라고 하는 방식이다. 이 방식에서는 힙에서 정렬 값으로 삼는(그래서 처리 순서에 영향을 주는 값)휴리스틱 변수에 현재까지 계산된 진행된거리 + 목표셀까지의 직선거리를 합산한 방식을 사용한다.

이책을 읽으며 -

허프만트리압축 메모

빈도 역순으로 정렬하는 힙에 삽입된 노드들이 차례로 2개씩 쌍으로 인출되서, 한 부모를 모시는 하위 트리로 2개로 변화하게 된다. 그리고 새로 생긴 부모 트리는 자식들의 빈도를 합산한 빈도값을 지니게 된체로 다시 힙으로 들어간다. 이 방식을 통해서 잦은 값은 상위 레벨에, 드문 값은 점점 트리 하위 레벨로 가게 된다. 결과적으로 그래서 잦은 값은 적은 비트로 표현하고, 드믄 값은 그보다 많은 비트로 표현하겠다는 것 같은데, 출현값들의 테이블의 인덱스를 압축코드로 쓰면서 경제적인 가변길이 인덱스를 지원한다고 말하는게 더 맛이 나는 것 같기도 하다.

이책을 읽으며 -

간단히 순서를 정리하자면, 우선 [데이터][빈도] 이렇게 구성되는 빈도표를 구성하고 간 항목을 빈도값을 역순으로 비교하는 힙에 넣는다. 그런 후에 2개씩 빼서 허프만 트리 만들기 알고리즘을 실행하고, 완성된 허프만 트리에서 실제 [데이터][허프만속성] 모양으로 변환표를 구성해서 압축할때 이표를 참조해서 간단히 허프만 코드로 변환한다. 압축 해제할때 허프만 트리가 필요하니, 트리는 배열 형태로 변환 후 허프만코드 파일에 같이 저장한다.

힙트리 메모

힙트리는 조밀해야 한다. 또한 부모와 자식 노드 사이의 크기 관계가 모든 노드에서 같아야 한다.
다시 말해서 부모 노드가 자식 노드보다 크기로 했으면 다른 모든 노드에서도 그 조건이 만족 되어야 한다.

이책을 읽으며 -

다차원 배열을 이용한 유한상태기계...

int [상태][사건][조건상태1][조건상태2] .... 이런 식으로 사용하는 거란 말이던데, 다른 방식들보다 기억에 남는다. 인상적이랄까... 상태에 따른 AI루틴 전에, 사건 발생 조건 검사해서, 상태 전이부터 처리해줘야 한다는 순서도 인상적이다.

이책을 읽으며 -


타일맵 자료 구조에 대한 이상한 생각 정리

쉽게 생각하기 위해서, 이동을 타일 단위로 한다고 하고, 이동 기능을 위해서 뭐가 필요한가 정리해보면 방향값이 하나 필요하다는 것을 적어두고, 현재 타일 에서 해당 방향으로 이어진 타일에 접근할 수 있는 자료 구조가 필요하다. 만약 64X64 정도의 초소형 타입맵이고, 그 중 거의 전부를 사용하는 꽉찬 맵이라면 그냥 배열로 관리하는 것이 합리적이나, 1024X1024 정도의 대형 크기에 실제로 캐릭터가 이동 가능한 면적은 전체 대비 15% 정도 밖에 되지 않는다면 배열을 사용하는 것은 다소 비합리적이다. 이럴때는 각 타일이 각 방향별로 연결된 타일들을 유일하게 지목할 수 있는 자료구조를 (물론 그림도 그렇게 그려져야 하고, 그리고 그릴때는 그냥 다 다 그려버리면 된다) 가지면 해결이 된다. 머리 아프면 그냥 다 다차원 배열로 관리하면 된다. 램값도 싼데...

이책을 읽으며 -


이상한 정리 - diff & patch, 그리고 hunk


우선 사용법은 여기에.

hunk라는 개념이 나오는데, 기본적으로 변화가 시작 되기 직전 세줄과, 변화가 끝난 직후 세줄 그리고 변화가 이루어진 부분 이 3부분을 통째로 합쳐서 hunk라는 논리 단위로 호칭한다.

patch 에러메세지를 보면 hunk 번호가 나오는데 변화가 일어난 덩어리 단위로 청크 번호를 생각해서 찾으면 된다. 기본 값은 위로, 아래로 3줄까지 하나의 헝크에 넣는데, 헝크 끼리 겹치면 하나의 헝크로 합친다. 이렇게 합쳐진 헝크는 사이에 변화 없는 행이 껴있는 여러개의 변화 덩어리를 보유하게 되는 모양이 된다.

이책을 읽으며 -


갈증

어떤 갈증으로부터 벗어나는 길은 물을 마시는 방법이 하나 있고, 더 강렬한 갈증에 휘말리는 방법이 하나 있다.

이상하게 정리하기

논리 주소를 물리 주소로 사상 시키는 방법에는 그 시기에 따라 컴파일 시간 바인딩 방법, 메모리 적재시 바인딩 방법, 실행 시간 중 바인딩 방법이 있다고 한다. 컴파일 시간 결정 방법과 적재시 바인딩 방법에서는 실행 전에 논리 주소가 물리 주소로 치환된 형태가 된다. 따라서 프로세스가 자신이 접근하는 실제 물리 메모리 주소를 알 수 있게 된다. 그러나 실행 시간 중 바인딩 방법은 보통 메모리 사상 전용 하드웨어의 지원 위에 구현되며, 논리 주소를 통한 접근이 그 이 장치를 통해 물리 주소로 실시간 변환이 되는 구도이다. 따라서 프로세스가 실제 자신의 논리 주소가 사상되는 물리 주소를 알기 힘들다.

이책을 읽으며 -

어떤 책을 살 것인가?

어떤 책을 살 것인가? - 이제 나는 단 하나의 질문으로 살책들을 가려내기로 했다.
"그 책을 도서관에서 빌려본 후 다시 보기 위해서 도서관에서 재대출을 하러갈 동기가 생기는가?" 그래 좋다!, 그럼 사도 된다,
그러나 그런 동기가 형성되면 빌리러 가면 된다. 그러므로 살책은 거의 없는 셈이다.

bash에서 - $*과 "$*"는 다르다


$* 매개변수가 큰따옴표 안에서 확장할때는 매개 변수들이 하나의 문자열로 확장된다.
참고 - http://www.ibm.com/developerworks/kr/library/l-bash-parameters.html

따라서,
echo $*와 echo "$*"가 다른 출력 결과를 만들 수 있다. 그리고 "$*"의 경우 IFS의 첫문자로 매개변수들을 구분하는 문자열을 만드는 것 같다. 이런 차이는 echo 명령어로는 확인하기 어렵고, for 문으로 돌려보면 확실하게 눈으로 보이는 것 같다. 참조 링크를 보시면 훌륭한 예제도 나와있다. 차이가 애매하다 인자를 이런식으로 다룰 필요 있을때는 링크한 문서 참조해서 작업해야겠다.












이책을 읽으며

, which가 들어간 영어 문장

관계대명사의 계속적 용법이란 용어로 정리된 잘 알려진 영어 패턴을 몰라서 쉽게 넘어갈 수 있는 부분에서 시간을 많이 소모했다. 간단히 정리해 두자면 콤마(,)가 이끄는 관계사절은 선행사가 포함된 문장과는 독립된 문장이라고 보며 따라서 콤마 전에 문장은 이미 하나의 뜻을 완성하고, 관계사절은 그에 부과적인 의미를 덧붙이는 형식이라는 점이다. 물론 관계대명사가 선행사의 대명사 역활을 한다는 점에는 두 용법 사이에 차이가 없다. 제한적 용법은 선행사가 포함된 문장에 뜻이 형성되는 과정에 관계사절이 영향을 미치는 경우다.

이 블로그에 정리가 잘 되어 있었다.

전역 공간상의 자료 조작 수필

전역에서 접근 가능한 메모리 공간에 자료를 두고 어디서든 접근해서 조작 및 참조 하는 일은 거의 반드시 발생하는 프로그램 개발 내용의 일부분인 것 같다.


어셈블리언어 주소 지정 방식 - 간접 어드레싱


MOV DL, 77    ;    수치 77을 DL 레지스터에 넣는다.
MOV DL, [77] ;    오프셋 77에 있는 값을 DL 레지스터에 넣는다. 이와같은 주소 지정 방식을 간접 어드레싱이라 한다.

- 이와같은 간접 어드레싱에 사용할 수 있는 레지스터는 BX,BP,SI,DI로 한정된다. 예를들어

MOV BX, 77
MOV DL, [BX]    ;    오프셋 77에 있는 값을 DL에 넣는다.

MOV AX, 77
MOV DL, [AX]    ;     가능하지 않다.


- LEA 명령어

LEA Op1, Op2
기능 : Op2의 시작 오프셋 주소를 op1에 기록한다.


LEA    SI,    DataLabel                ;    이는 
MOV   SI,    OFFSET DataLabel   ;    이라 해도 된다. DataLabel의 시작 오프셋 주소를 SI에 기록한다.

LEA SI, [77h]    ; 이는
MOV SI, 77h      ; 와 같다.


어셈블리 못해먹겠다. 책만 대충 보고 잊어야지 -_-


자 이제 2D 라이브러리 고민 시작! 수필


움직이는 것들은 죄다 객체화 시켜버릴테고, 녀석들은 자신을 그리고 싶어할 것이고

똑같은 모습을 그릴 녀석들도 있을 것이고, 그럼 그걸 위해서 똑같은 그림을 2번 로딩하는건 낭비일 것이고

그래서 스프라이트들을 중앙 집중적으로 관리하는 객체가 필요할 것이고,

각 개체마다 그 스프라이트들을 이용할 수 있게 해주는 객체도 필요할 것이고

또한 각각의 스프라이트들을 그룹별로 묶어서 애니메이션 시켜주는 기능이 필요할 것 이고,

애니메이션은 멈추거나 루프가 가능해야 할 것이고, 색을 바꾸거나 할 수 있어야 할 것이고

애니메이션은 속도도 조절가능해야 할 것이고(FPS수치등으로),

-

Dog 객체와 Cat 객체를 만들어서 모니터를 마음데로 돌아다니는 모습을 그린다고 가정해보면

우선 걷는 동작이 부드럽게 이어지는 스프라이트들을 갖고 애니메이션 시키면서 표시하는 위치를 바꾸어야 할 것이다.

방향이 바뀌면 다른 애니메이션이 출력되야 할 것이다.

SetTextureStageState 수필

http://msdn.microsoft.com/en-us/library/ms886501.aspx
http://msdn.microsoft.com/en-us/library/ms886612.aspx
정리하기 위해서 우선 이 두 글이 필요하다.

SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
 
SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);

첫 번재 링크 문서에 따르면 MODULATE 연산은 인자끼리 곱해버리는 연산이다.
.
.
아마 255를 1로, 0을 0으로 변환해서 곱하는 것 같다.

가정이 맞다면
만약 곱해지는 인자가 255,255,255 였다면 아무런 변화도 일어나지 않고
만약 곱해지는 인자가    0,   0,   0 이었다면 검은색 화면만 보일 것이다.
원래색을 어둡게 하거나 혹은 유지시키는 연산이다.


Diffuse값을 변화시킴으로써
텍스처에 색깔 효과나 알파 조절 효과를 도모할 수 있는 방식인 것 같다.



알파 블렌딩 수필

기존에 출력되어 있던 것과 혼합되어 출력하게 하는 기능으로, 우선 켜야 한다.
SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); 이렇게.

섞는 방법은 다양하다.

  • D3DBLENDOP_ADD
  • D3DBLENDOP_SUBTRACT
  • D3DBLENDOP_REVSUBTRACT
  • D3DBLENDOP_MIN
  • D3DBLENDOP_MAX

이러한 섞는 방식이 제공되며, 다음과 같이 설정할 수 있다.

SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_REVSUBTRACT)

.
.
.

기본값은 D3DBLENDOP_ADD가 되겠다.
.
.
.
그런데 섞는 방식만 선택할 수 있는 것이 아니다.
섞이는 두 데이터에 가중치를 어떻게 선택하여 서로 혼합하는가에 따라서 여러가지 종류로 나누어진다.

D3DBLENDOP_ADD 합성 방식을 사용하면서, 가중치에 변화를 주어서 여러 스타일의 혼합이 가능하다. 그러나 기본적으로
두 색을 더한다는 큰 그림에는 변화가 없다. 대표적인 스타일로 선형 방식은 D3DBLENDOP_ADD 합성 설정 하에서

SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

로 가중치를 주어서 합성하는 방식이다.


Alpha Testing. 수필


일종의 컬러키, 주된 역활은 알파-혼합의 연산 대상 픽셀을 줄이는 것이다. 다시 말해 거의 혹은 완전히 투명한 부분의 혼합 연산을 생략할 수 있는 조건을 다음과 같은 코드로 지정할 수 있게 한다.

if (pCaps.AlphaCmpCaps & D3DPCMPCAPS_GREATEREQUAL)
{
     dev->SetRenderState(D3DRS_ALPHAREF, (DWORD)0x00000001);
     dev->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);
     dev->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL);
}

이와 같은 형태로 지정하며 ALPHAREF 값은 0X00000000~0X000000FF 까지 지정할 수 있으며 이는 알파값이다.
비교 함수 형태로 D3DCMP_GREATEREQUAL이 지정되어 있다면 알파값이 0X00000001보다 작은 픽셀값은 혼합 연산을 아예 생략해 버린다. 따라서 텍스처에 알파값이 들어가 있어야 하는 것 같다.

0X00000001보다 작다라는 조건은 다시 말해서 완전히 투명한 경우 0X00000000 만 해당되는 것이고 풀어 말하자면 완전히 투명한 부분의 혼합 연산은 생략한다는 설정인 것 같다.


DrawPrimitiveUp() vs DrawPrimitive() 수필

DrawPrimitiveUp() 함수는 정점 버퍼를 요구하지 않고 시스템 메모리상의 정점 정보만으로 그려주는 함수이고
DrawPrimitive() 함수는 미리 생성되야 하는 정점 버퍼를 요구한다.

정점 수가 적다면 속도차는 무의미하다.




VC 6.0을 지원하는 SDK 조합 수필

VC 6.0을 지원하는 마지막 플랫폼 SDK는 2003년 Feb 버전인것 같고
VC 6.0을 원활하게 지원하는 버전으로 DirectX SDK는 2003 Summer 를 선택하면 무난할 것 같다.


조리개와 심도


1. 조리개 값이 작을수록(개방될수록) 심도가 낮다.

2. 같은 조리개 값이면 광각보다 망원이 심도가 낮다.(아웃포커싱이 좋다)

3. 내 번들 렌즈는 망원이 되면 최대 조리개 수치가 커진다.
    따라서 망원에 따른 아웃포커싱 효과 증가와 상쇄되는 측면이 있다. 다시 말해 망원과 광각의 심도 차가 작다.

4. 거리가 멀어지면 심도가 깊어진다.

-

조리개가 고정된 밝은 줌렌즈를 사고 싶어라.
이런거...http://blog.danawa.com/prod/142077/C/842/1157/1230/0

richedit 컨트롤 마지막에 문자열 추가 하기. 수필


[org 0x7C00]의 의미. 수필


1.우선 리얼모드에서는 메모리 어드레스가 20비트라는 점
{
    주소를 16비트 레지스터 들을 갖고 표현하기 위해서
    Segment Base : Offset Address 형태로 표현한다는 점
    ex)
        1000        - Segment base
         2345       - Offset address
       -------
        12345
}

2. BIOS에서 0x07C00 주소에 부트섹터를 로드해놓고 jmp 0x0000:0x7C00 (0x07C00) 한다는 점.

3. 바이너리 프로그램 입장에서는 자기가 어느 메모리 주소로 로딩되서 실행될지 예측할 수 없다는 점

4. 소스내에서 JMP LABEL 했다면 LABEL의 주소는 기본적으로 상대주소를 갖는다는 점
   여기에 만약 [ORG] 명령으로 오프셋 기준을 만들어주면 모든 상대 주소에 이 값이 더해진다는 점.


부모프로세스가 종료되면 자식프로세스의 부모는 INIT프로세스 (pid=1)로 바뀝니다 수필

부모프로세스가 종료되면 자식프로세스의 부모는 INIT프로세스 (pid=1)로 바뀝니다

참조
http://kldp.org/node/85257

WSAAsyncSelect 수필

The WSAAsyncSelect function automatically sets socket s to nonblocking mode, regardless of the value of lEvent.

전에 사용하던 코드를 살펴보니 FD_WRITE 플래그를 사용하지 않는다.
왜 사용 안하나? - 소켓 송신 버퍼가 FULL 이 아닐때 계속 신호가 오니깐, 거의 계속해서 신호가 오겠군, 이게 답인가?
하기사 클라이언트가 서버로 보내면 얼마나 보낼것인가~

틀렸다. FD_WRITE는 쓰기 불능 상태에서 가능 상태로 전이가 일어났을때 생긴다고 한다.
찾았다!

The FD_WRITE event is handled slightly differently. An FD_WRITE message is posted when a socket is first connected with connect or WSAConnect (after FD_CONNECT, if also registered) or accepted with accept or WSAAccept, and then after a send operation fails with WSAEWOULDBLOCK and buffer space becomes available. Therefore, an application can assume that sends are possible starting from the first FD_WRITE message and lasting until a send returns WSAEWOULDBLOCK. After such a failure the application will be notified that sends are again possible with an FD_WRITE message.

WSAEWOULDBLOCK
This error is returned from operations on nonblocking sockets that cannot be completed immediately, for example recv when no data is queued to be read from the socket. It is a nonfatal error, and the operation should be retried later.

send() 함수 호출시 송신용 소켓버퍼가 가득 차있다면 WSAEWOULDBLOCK이 리턴되는 모양이다. 따라서 보다 안정적인 송신을 위해서는 송신용 데이터도 환형큐에 넣고 FD_WRITE가 왔을때 송신 허락 플래그를 On으로 세팅하고 다시 WSAEWOULDBLOCK이 리턴되면 플래그를 Off로 설정해야겠다.


종료 처리 중첩 방지를 위한 참조 카운팅 수필

어떤 소켓에 WSARecv와 WSASend 연산이 동시에 걸려 있을 경우, GetQueuedCompletionStatus 함수를 통해 2번의 리턴이 예약되어 있는 셈이다. 그런데 우선 리턴된 연산이 종료 상태를 가르킨다 하여 바로 종료 처리를 하게 되면 위험할 수 있다.(하지만 구조에 따라선 종료 처리가 2번 되어도 문제 없을 수도 있다. 그래도 연산의 중복이라는 측면에 깔끔하지 않음으로 정리하는 것이 나을 것이다.)

Accept 이후의 과정에서 WSARecv나 WSASend 함수를 성공적으로 호출했을시 참조값을 올려주고, GetQueuedCompletionStatus 함수에서 리턴되는 순간에 참조값을 감소 시키면 될 것 같다. 또한 close 처리 여부를 기록하여, 참조 카운트가 0일때 close 처리를 하는 부분에서 참고하고 이 부분은 크리티컬 섹션 블럭으로 동시 접근을 차단하는 구조여야 할 것 같다.

GetQueuedCompletionStatus - from MSDN 수필

Return Value

If the function dequeues a completion packet for a successful I/O operation from the completion port, the return value is nonzero. The function stores information in the variables pointed to by the lpNumberOfBytes, lpCompletionKey, and lpOverlapped parameters.


If *lpOverlapped is not NULL and the function dequeues a completion packet for a failed I/O operation from the completion port, the return value is zero. The function stores information in the variables pointed to by lpNumberOfBytes, lpCompletionKey, and lpOverlapped. To get extended error information, call GetLastError.

If *lpOverlapped is NULL and the function does not dequeue a completion packet from the completion port, the return value is zero. The function does not store information in the variables pointed to by the lpNumberOfBytes and lpCompletionKey parameters. To get extended error information, call GetLastError. If the function did not dequeue a completion packet because the wait timed out, GetLastError returns WAIT_TIMEOUT.


1 2