본문 바로가기

진리는어디에

Edge trigger vs Level trigger

문제 :
  read가 가능한지를 알아 보기위해 select를 호출 하고 wait time을 NULL로 주어 무한히 대기 하게 했다.
  하지만 어찌 된 일인지 아무런 입력이 없을때는 가만히 있다가 한번 입력을 하고 나면 입력 read가 가능 하다는 메시지가 미친듯이 나오기 시작했다.
  코드를 잠시 살펴 보자면 아래와 같다.

 fd_set rset;
 FD_ZERO(&rset); // 0 은 stdin을 나타낸다.
 FD_SET(0, &rset);

 while(1) {
        fd_set tmp_rset = rset;
 
        int state = select(1024, &tmp_rset, &tmp_wset, NULL, NULL);

        if(state > 0) {
            for(int fd=0; fd<1024; fd++) {
                if(FD_ISSET(fd, &tmp_rset)) {
                    std::cout << "read" << std::endl;
                }
            }
        }
    }

 위와 같이 코드를 작성하면 처음은 괜찮다가 한 글자라도 입력을 받게 되면(입력을 받을 것이 있다고 알려지면) 미친듯이 read를 출력해대기 시작한다.

 왜 그럴까?

 우리의 천재 해결사 pudae군의 말을 따르자면 입력을 읽어 들이는 방식에는 edge trigger와 level trigger 이렇게 두 가지 방식이 있다고 한다.
 시그널에 있어서 edge는 신호가 바뀌는 지점을 말한다. 만일 신호가 바뀌는 그 시점을 catch하고 싶다면 edge trigger를 사용하고, 신호가 일정 level에 머물러 있는 것을 알아 내고 싶다면 level trigger를 사용 하면 된다. 결론은  아래와 같다.

 * Edge Triggered event
   이벤트(변화)가 발생 했을때만 리턴
 * Level Triggered event
   버퍼에 입력 받을 것이 있을 경우에는 그것이 없어질 때 까지 리턴
 
 위의 select는 Level Triggered event를 사용하는 있다고 한다.
 그렇다면 처음 입력이 들어온 경우가 일정한 level에 도달한 상태가 되고, 그것을 읽어 버퍼를 비워 주는 과정이 없으니 계속적으로 일정 level 이상의 상태가 된다. 그렇기 때문에 select 함수는 미친듯이 읽어 들일 것이 있으니 어서 읽으라고 소리치는 것이다.
 
 그럼 코드를 아래와 같이 변경해 보도록 하자.
 fd_set rset;
 FD_ZERO(&rset); // 0 은 stdin을 나타낸다.
 FD_SET(0, &rset);

 while(1) {
        fd_set tmp_rset = rset;
 
        int state = select(1024, &tmp_rset, &tmp_wset, NULL, NULL);

        if(state > 0) {
            for(int fd=0; fd<1024; fd++) {
                if(FD_ISSET(fd, &tmp_rset)) {
                    //std::cout << "read" << std::endl;
                    char buffer[1024];
                int n = ::read( 0, buffer, 1023);
                buffer[n] = '\0';
                std::cout << "read : " << buffer << std::endl;
                   
                }
            }
        }
    }

 붉은색 부분이 변경 된 곳이다. 위 처럼 버퍼에서 읽어들이는(비록 완벽하게 읽는 것은 아니지만) 코드를 삽입한다면 더 이상 select 함수는 미친듯이 메시지를 출력 해대지 않을 것이다. 다만 한번의 입력에 한번의 read 메시지를 출력 하겠지..

참고 :
 http://kldp.org/node/74537
 http://www.die.net/doc/linux/man/man4/epoll.4.html

email : kukuta@gmail.com
유익한 글이었다면 공감(❤) 버튼 꾹!! 추가 문의 사항은 댓글로!!