2013-04-18 7 views
3

을 설정하고 당신이 그것을 FDS 때문에 제대로 0, 1을 작동하지 않습니다 터미널에서 실행하려고하면 나는 다음과 같은 예를내가는 epoll을 사용 배우고

#include <assert.h> 
#include <errno.h> 
#include <fcntl.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <sys/epoll.h> 
#include <unistd.h> 

int main() { 
    int epfd; 
    struct epoll_event ev; 
    struct epoll_event ret; 
    char buf[200]; 
    int n,k,t; 

    epfd = epoll_create(100); 
    assert(0 == 
      fcntl(0, F_SETFL, fcntl(0, F_GETFL) | O_NONBLOCK) 
     ); 

    ev.data.fd = 0; 
    ev.events = EPOLLIN | EPOLLET; 

    if(epoll_ctl(epfd, EPOLL_CTL_ADD, 0, &ev) != 0) 
     perror("epoll_ctl"); 


    while((n = epoll_wait(epfd, &ret, 1, -1)) > 0) { 
     printf("tick!\n"); 

     if(ret.data.fd == 0) { 
      k=0; 
      while((t=read(0, buf, 100)) > 0) { 
       k+=t; 
      } 

      if(k == 0) { 
       close(0); 
       printf("stdin done\n"); 
      } 
     } 
    } 

    perror("epoll"); 
    return 0; 
} 

을 쓴 2는 모두 같은 열린 파일을 가리키고 있으므로 close (0)는 epoll 세트에서 stdin을 제거하지 않습니다. "cat | ./a.out"을하면이 문제를 해결할 수 있습니다. 더러운 속임수, 알아, 명명 된 파이프 또는 소켓 작은 예제를 설정하는 것은 더 복잡합니다.

이제 모든 것이 작동하고 파일이 epoll 세트에서 제거되지만 다음 epoll_wait 호출은 빈 세트에 있기 때문에 영구적으로 차단됩니다! 따라서 epoll 파일 설명자 (epfd)가 빈 epoll 세트인지 여부를 감지해야합니다.

어떻게이 문제를 해결할 수 있습니까? (일반적인 방법으로 stdin이 끝났을 때 exit 만 호출하는 것이 아닙니다) 감사합니다!

+0

"제대로 작동하지 않는다"고 말할 때 정확히 무엇을 기대합니까? 'epoll_wait'가 stdin이 닫히고'while' 루프가 종료 된 후에 실패 할 것인가? –

+0

@AustinPhillips ./a.out으로 프로그램을 시작하면. 파일 기술자 0, 1 및 2는 모두 동일한 열린 파일 (터미널)을 참조합니다. 그래서 epoll은 fd가 아닌 열려있는 파일들과 작동하기 때문에 stdin (0)을 닫는 것은 효과가 없습니다. 'man epoll '의 질문 6은이 점을 더 잘 설명합니다. 'cat | ./a.out', 이제 fd 0은 파이프이고 fd의 1과 2는 터미널입니다. – Guido

+0

예상 한 내용을 설명하지 않았습니다. 설명서 페이지의 A6에서 설명하는 것처럼, '파일 설명'에 대한 참조가 더 이상 없을 때 파일 설명자는 epoll 세트에서 제거됩니다. 'close (0)'하면 아마 프로그램에 계속 관심이 없습니다. 이 경우, epoll 세트에서'EPOLL_CTL_DEL' fd 0을 할 수 있고,'epfd'에서 미해결 파일 디스크립터의 수를 세는 카운터를 어딘가에 줄여서 0에 도달하면 프로그램을 종료 할 수 있습니다. –

답변

0

기본적으로 epoll을 "올바르게"사용하는 경우 예기치 않게 빈 epoll 세트가 발생하지 않아야합니다. 할 일이 더있을 때를 알 필요가 있습니다. 글쎄, 그건 적어도 이론이야. 내가 그것을 보자 :

당신은 여기에 EPOLLET을 사용하고있다 (즉, imho, 오른쪽은 일반적으로 생각한다). 이것은 파일 디스크립터 0이 &ret에 반환 될 때 epoll에서 제거되었음을 의미합니다. 이 시점에서 당신은 0에서 데이터의 일부분을 읽음으로써 처리해야하지만, 파일 설명자 0을 epoll에 다시 추가하여 "다시 활성화"합니다 (물론 닫혀 있지 않은 한). 이것이 어떻게 작동해야하는지에 대한 예를 보려면 내부 루프를 제거하고 다음을 수행하십시오.

k = read(0, buf, 100); 

최대 100 바이트를 읽는 것. 생각보다 큰 파일을 파이프하면 전체 루프를 통해 여러 번 이동해야합니다. 이 작업을 수행하려면 k> 0 인 경우 k 바이트를 처리 한 후에 epoll_ctl(..EPOLL_CTL_ADD..)에 다시 전화해야합니다.

성가신 세부 사항을 참고하십시오. read()은 0 바이트를 반환하지만 파일이나 소켓이 끝에 오지 않을 수도 있습니다. errno == EAGAIN || errno == EWOULDBLOCK을 확인하십시오. 그 케이스를 감지하고 다시 epoll_ctl(..EPOLL_CTL_ADD..).

+0

"여기에서는 EPOLLET을 사용하고 있습니다 (즉, imho는 일반적으로 생각합니다.) 이것은 파일 설명자 0이 &에서 반환 될 때 epoll에서 제거되었음을 의미합니다." 미안하지만 이건 틀렸어, 너는 epoll이 EPOLLONESHOT을 혼란에 빠뜨리는거야? – Guido

+0

죄송합니다. 나는 EPOLLONESHOT에 대해 잊고 있었고 그것이 EPOLLET에 의해 암시되었다고 가정했다. 미안합니다; 내 설명은이 경우에 대한 것이므로 코드에 오류가있는 것으로 생각했기 때문에 설명을주었습니다. 반면에 아무 것도 없습니다 (다른 방법 일뿐입니다). –

-1

추가 된 모든 항목을 제거하면 epoll 세트가 비어있게됩니다. 필자가 아는 한, epoll 세트를 내성적으로 검사하여 파일 설명자가 있는지 여부를 확인할 수 없습니다. 따라서 Armin의 대답에 명시된대로 epoll 세트가 비어있게되는 시점을 결정하는 것은 개발자의 몫입니다.

프로그램에서 예상 한 내용을 설명하지 않았기 때문에 close(0)을 실행하면 파일 설명자 0이 epoll 세트에서 제거 될 수 있기 때문에 stdin이 닫히면 종료 될 것으로 예상됩니다. . 그러나 나열된 코드에는 결함이 있습니다. 자동적으로 제거되는지 또는 EPOLL_CTL_DEL를 사용하여 파일 설명자를 포함하지 않는 epoll 세트에서 계속 대기하는 경우 epoll_wait은 영원히 기다립니다.

다음 코드는이 점을 잘 보여줍니다.

#include <errno.h> 
#include <stdio.h> 
#include <sys/epoll.h> 

int main() { 
    int epfd; 
    int n; 
    struct epoll_event ret; 

    epfd = epoll_create(100); 

    while((n = epoll_wait(epfd, &ret, 1, -1)) > 0) { 
     /* Never gets here. */ 
     printf("tick!\n"); 
    } 

    return 0; 
} 

epoll 파일 세트는 파일 기술자를 포함하지 않는, 그래서 epoll_wait 영원히 기다립니다. 프로그램에서 stdin에 파일을 연결하고 프로그램의 다른 파일 디스크립터를 stdin에 연결 한 경우 close(0)은 세트에서 fd 0을 제거하고 epoll 세트는 비어있게되며 다음 epoll_wait은 영원히 기다립니다.

일반적으로 파일 디스크립터는 epoll 세트에서 직접 관리하며 close 호출에 의존하지 않고 파일 디스크립터를 자동으로 제거합니다. close(0)을 실행 한 후에 epoll 세트에서 계속 대기할지 여부를 결정하는 것은 개발자의 몫입니다.

read 다음에 프로그램 구조를 epoll_wait으로 변경하는 것이 좋습니다. 이렇게하면 epoll_wait으로 처음 전화하기 전에 표준 입력에 도달했을 수있는 모든 데이터를 얻을 수 있습니다. 당신이 연속적으로 100 0 다음 반환 루프에서 read 일부 데이터 플러스 파일의 끝을 나타내는 것으로 가정하면

k=0; 
while((t=read(0, buf, 100)) > 0) { 
    k+=t; 
} 
if(k == 0) { 
    close(0); 
    printf("stdin done\n"); 
} 

close(0)가 호출되지 않습니다 :

또한이 같은 코드주의 . 프로그램이 반복되어 epoll_wait에 영원히 다시 대기합니다. 파일의 끝과 오류에 대해 각 read의 결과를 확인하는 것이 가장 좋습니다.