아.. nonblocking을 한글로 뭐라고 표현해야 될지 모르겠다.

대충 풀어서 쓰자면 입력을 요구하되, 기다리지는 않는다는 뜻이다. 무슨 소린가 하면, C로 프로그래밍을 조금이라도 해본 사람은 알 것이다. gets 같은 함수로 입력받기를 기다린다고 하자. 그럼 이 gets는 실제로 입력이 들어올 때까지 끝나지 않는다.

gets(first);
printf("첫 번째 입력이 들어왔습니다. ?\n");
gets(second);

first 입력을 완료하기 전까지 2번 줄의 printf는 결코 실행되지 않으며, 따라서 second 입력도 받을 수 없다. gets는 사용자가 입력을 완료할 때까지 끝나지 않는 것이다. 이것이 Blocking 입력이다.

반대로 Nonblocking은, 입력이 들어왔는지 조사는 하지만 입력이 있건 없건 진행된다. 넌블럭킹 입력 같은 경우는 프로그래밍 초보자가 다룰 주제가 아니기 때문에 교양 수준으로 배운 사람들이라면 생전 처음 듣는 소리일 것이다. 넌블럭킹 입력의 쓰임을 가상코드로 표현해보면 대충 이렇다.

// 입력이 있든 없든 이 함수는 결과값을 즉시 반환한다(고 치자)
input = check_if_input_exists(stdin); 

if(input == true) printf("요태카지 날 미앵한고야?\n");
else /* input == false */ printf("논 자유에 모미 아냐 요태카지 그래와코 아페로도 개속\n");

즉 넌블럭킹 입력은 (지나치게 단순화한 것이긴 하지만) 입력이 반드시 있다고 가정하는 것이 아니라, 입력이 있을 수도 없을 수도 있는 경우에 쓸 수 있는 놈이다. 혹은 입력이 언젠가는 있겠지만, 그거 무한정 기다리고 있을 만큼 한가하지 않다면, 언젠가 들어올 입력을 기다리는 동안 다른 일을 하고 있어야 마땅하다.

넌블럭킹과 블럭킹의 차이를 이해하기 가장 쉬운 예가 게임이다. 턴제 전략게임 - 중에 가장 유명한 - 바둑을 두고 있다고 치자. 바둑은 블럭킹의 예를 들기에 가장 적합한 케이스다. 내가 돌을 두기 전까지는 결코 상대방 차례가 오지 않기 때문이다(물론 시간제한 없는 룰일 경우다). 반대로 내 차례라는 것이 애당초 없는 스타크래프트는 넌블럭킹의 예를 들기에 (사실 조금은 부적합하지만) 좋다.

아무튼 잡설은 그만하고..


그런데 블럭킹 입력과 달리 넌블럭킹 입력은 운영체제에 몹시 의존적이다. 코드 하나 짜 놓고 이리저리 돌려쓰기를 좋아하는 나 같은 사람에게는 몹시도 슬픈 얘기다.


그러니까 안짜도 될 코드 짜서 짜증이 났다 그 소리다.

/**
    윈도우즈에서 Nonblocking 입력을 몹시 하고 싶어서 만들었다.
    
    @author hoppang at gmail dot com
    @date 2010-01-27
    @version 9999
    @a http://hoppang.net
 */

#include<cstdio>
#include<windows.h>

int main()
{
    int count = 0;
    DWORD result, how_many_read;
    INPUT_RECORD input;
    HANDLE stdin_handle;
    // stdin의 윈도우식 핸들을 구한다.
    stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
    // 각 
    bool shift_state = false, alt_state = false, ctrl_state = false;
    // 자 루프를 돌자
    for(;;){
        /*
            WaitForSingleObject는 키보드 입력에만 쓰이는 놈은 아니다.
            자세한 것은 MSDN을 찾아보고.. 아무튼 여기서는 유닉스의 select를
            대체할 수 있다.
            두 번째 인자(시간)가 0일 경우 입력 버퍼에 아무것도 없어도
            입력을 기다리지 않고 즉시 리턴한다. (non-blocking)
         */
        result = WaitForSingleObject(stdin_handle, 0);
        /*
            들어온 입력이 있을 경우 WAIT_OBJECT_0이 반환된다.
            인터넷에서 어쩌다 본 문서에는 '모든 종류의' 이벤트를 감지할 수 있다고 했으나,
            실제 돌려본 바 그렇지는 않은 듯함. 키보드 입력만 받는다.
         */
        if(result == WAIT_OBJECT_0) {
            /* 입력 버퍼에서 입력을 읽어들인다.
             param 1 [in]    이름 보면 모르나
             param 2 [out]    받아들인 입력 정보가 저장될 구조체
             param 3 [in]    인자 2에 넘겨진 구조체가 몇 개인가.
             param 4 [out]    읽어들인 입력 정보가 총 몇 개인가. 문제가 없다면 인자 3과 같다.
             */
            ReadConsoleInput(stdin_handle, &input, 1, &how_many_read);
            /*
                조금 귀찮은 부분이다.
             */
            switch(input.Event.KeyEvent.wVirtualKeyCode) {
                case VK_ESCAPE:
                    return 1;
                case VK_SHIFT:
                    shift_state = input.Event.KeyEvent.bKeyDown;
                    break;
                case VK_MENU: // alt
                    alt_state = input.Event.KeyEvent.bKeyDown;
                    break;
                case VK_CONTROL:
                    ctrl_state = input.Event.KeyEvent.bKeyDown;
                    break;
                default:
                    if(input.Event.KeyEvent.bKeyDown == TRUE) {
                        printf("\ninput %x %s%s%s, how_many_read = %x\n",
                            input.Event.KeyEvent.wVirtualKeyCode,
                            shift_state ? "[shift]" : "",
                            alt_state ? "[alt]" : "", 
                            ctrl_state ? "[ctrl]" : "", how_many_read);
                    }
            }
        }
        // 입력이 없을 경우. 사실 이건 없어도 상관없는데
        // 프로그램이 멎어 있지 않다는 것을 보여주려고 집어넣었다.
        else printf("\r%10d", count++);
    }
    
    return 0;
}



크리에이티브 커먼즈 라이센스
Creative Commons License
2010/01/27 18:15 2010/01/27 18:15
Posted by 호빵

트랙백 주소
http://hoppang.net/tc/trackback/59

댓글을 달아 주세요

  1. 호빵 2010/01/29 16:09 PERMALINK M/D REPLY

    젠장 내가쓴 글인데 내가 수정을 못하네... ㅡㅡ

    중간의 VK_CONTROL 어쩌구 부분은, waitforsingleobject로 입력을 대기할 경우 특수키(modifier key) 입력까지 죄다 입력으로 처리해 버린다. 그래서 shift-a 같은 키 조합을 처리하려면 그 부분에 대한 코딩을 직접 해줘야 한다...

[로그인][오픈아이디란?]