《 Linux 시스템 프로 그래 밍 》 노트 제4 장 (2)

시리즈 글 목록:http://blog.csdn.net/wylblq/article/details/51841684
4.2 이벤트 폴 인터페이스
제2 장 - I / O 다 중 재 활용 기술 을 배 울 때 select () 와 poll () 두 시스템 호출 을 언급 했 습 니 다. 이 두 시스템 호출 은 여러 파일 설명자 에 막 혀 CPU 자원 을 양보 하고 해당 하 는 파일 의 읽 기, 쓰기 가 완료 되 거나 이상 이 발생 하 는 것 을 막 을 수 있 습 니 다.그러나 상기 두 시스템 호출 은 모두 잠재 적 인 문제 (구체 적 으로 대응 하 는 장 참조) 가 있 고 커 널 2.6 이후 epoll () 체 제 를 도입 하여 전에 언급 한 문 제 를 해결 하고 변두리 트리거 체 제 를 도입 했다.I / O 다 중 복용 모델 에서 epoll () 은 현재 가장 좋 은 방안 이다.
4.2.1 새로운 epoll 인 스 턴 스 생 성
epoll 인 스 턴 스 를 만 드 는 것 은 epoll 모델 을 사용 하 는 첫 번 째 단계 입 니 다.
#include <sys/epoll.h>
int epoll_create(int size);

이 함수 가 새 epoll 파일 설명 자 를 열 고 되 돌려 줍 니 다. 다음 epoll 작업 은 이 파일 설명자 로 진행 되 어야 합 니 다.매개 변수 size 는 원래 되 돌아 오 는 epoll 파일 설명자 가 초기 에 몇 개의 파일 설명 자 를 감청 할 수 있 는 지 지정 하 는 데 사용 되 었 으 나 Linux 커 널 은 감청 가능 한 파일 설명자 수 를 동적 으로 증가 시 킬 수 있 기 때문에 이 매개 변 수 는 새로운 커 널 버 전에 서 무 시 됩 니 다.2.6.27 커 널 버 전에 새로운 시스템 호출 int epoll_create1(int flags); 을 도입 하 였 으 며, 그 역할 은 epoll 입 니 다.create () 와 마찬가지 로 인자 flags 는 새 epoll 파일 설명자 의 속성 을 표시 합 니 다. 현 재 는 EPOLL_CLOEXEC 만 지원 합 니 다.이 호출 은 성공 할 때 epoll 파일 설명자 의 값 을 되 돌려 줍 니 다. 실패 할 때 - 1 을 되 돌려 주 고 errno 를 설정 합 니 다.주의해 야 할 것 은 epoll 파일 설명자 도 시스템 자원 을 차지 하기 때문에 더 이상 사용 하지 않 을 때 close () 를 호출 하여 닫 아야 합 니 다.파일 설명자 와 마찬가지 로 epoll 자원 에 대응 하 는 모든 파일 설명자 가 닫 혔 을 때 커 널 은 해당 하 는 자원 을 시스템 에 되 돌려 줍 니 다.
4.2.2 제어 epoll
epoll 인 스 턴 스 를 만 든 후에 우 리 는 되 돌아 오 는 파일 설명 자 를 사용 하여 어떤 파일 설명자 와 어떤 사건 을 감청 하 는 지 제어 할 수 있 습 니 다.
#include <sys/epoll.h>
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

처리 성공 시 0 을 되 돌려 주 고 실패 시 - 1 을 되 돌려 주 며 errno 를 설정 합 니 다.epfd - 열 린 epoll 파일 설명자 op - epfd 와 fd 에 대해 무엇 을 합 니까?
값 을 얻다
속뜻
EPOLL_CTL_ADD
fd 를 epfd 의 관심 목록 [^ 1] 에 추가 합 니 다. 즉, fd 를 감청 하고 감청 사건 은 이벤트 매개 변수 에서 설명 합 니 다.fd 호출 을 반복 하면 EEXIST 오류 가 발생 합 니 다.
EPOLL_CTL_MOD
관심 목록 의 fd 에 대응 하 는 epollevent 는 이벤트 매개 변수 로 덮어 씁 니 다. 존재 하지 않 는 fd 를 수정 하면 ENOENT 오류 가 발생 합 니 다.
EPOLL_CTL_DEL
fd 를 epfd 의 관심 목록 에서 제거 하고 이벤트 매개 변 수 는 무시 합 니 다.fd 가 close () 되 었 을 때 epfd 의 관심 목록 이 자동 으로 이동 합 니 다.존재 하지 않 는 fd 를 제거 할 때 ENOENT 오류 발생
fd - 작 동 할 파일 설명자, 대응 하 는 파일 은 FIFO, Socket, 파이프 일 수 있 습 니 다.메시지 큐, 터미널 등 이지 만 일반 파일 이나 디 렉 터 리 일 수 없습니다. 그렇지 않 으 면 EPERM 오류 가 발생 했 습 니 다.이벤트 - 감 청 된 이벤트 정보 와 사용자 데이터 struct epoll이벤트 구 조 는 다음 과 같 습 니 다.
typedef union epoll_data 
{
   void        *ptr;
   int          fd;
   uint32_t     u32;
   uint64_t     u64;
} epoll_data_t;

struct epoll_event 
{
   uint32_t     events;      /*      */
   epoll_data_t data;        /*      */
};

이벤트 대표 감청 이벤트 유형
값 을 얻다
속뜻
EPOLLERR
파일 오류, 이 사건 은 기본적으로 감청 되 었 습 니 다.
EPOLLET
다른 로고 와 작업 하거나 연산 하여 가장자리 트리거 를 엽 니 다.
EPOLLHUP
파일 이 걸 려 있 습 니 다. 이 사건 은 기본적으로 감청 되 었 습 니 다.
EPOLLIN
파일 작성 완료
EPOLLONESHOT
다른 표지 와 연산 을 하거나 한 번 감청 이 완 료 된 후 이 파일 설명 자 는 감청 되 지 않 습 니 다.EPOLL 을 사용 하지 않 는 한CTL_MOD 가 감청 사건 을 다시 설정 합 니 다.
EPOLLOUT
파일 작성 완료
EPOLLRDHUP
socket 통신 중 엔 드 닫 기
EPOLLPRI
높 은 우선 순위 외부 데이터 읽 을 수 있 습 니 다.
epoll_data 는 유 니 온 형식의 데이터 입 니 다 [^ 2].사용자 정의 정 보 를 저장 하 는 데 사 용 됩 니 다. 파일 설명자 가 준비 되면 이 데 이 터 는 사용자 에 게 되 돌아 갑 니 다. 감청 된 파일 설명 자 를 epoll 에 할당 하 는 것 이 자주 사 용 됩 니 다.event.data.fd。또한 안전 을 보장 하 는 전제 에서 처리 함수 의 주 소 를 ptr 에 할당 할 수 있 습 니 다.epoll_ctl () 은 관심 있 는 파일 설명자 와 감청 이 벤트 를 커 널 공간 으로 복사 합 니 다. 한 번 만 호출 하면 됩 니 다. 매번 select () 와 poll () 호출 은 파일 설명자 정 보 를 커 널 로 복사 해 야 합 니 다.epoll 때문에ctl () 에 추 가 된 파일 설명 자 는 커 널 공간 을 차지 하기 때문에 리 눅 스 는 감청 파일 설명자 의 최대 수량 을 규정 하고 파일 /proc/sys/fs/epoll/max_user_watches 에 규정 합 니 다.
4.2.3 epoll 이벤트 대기
epoll 인 스 턴 스 를 만 들 고 epoll 감청 파일 설명자 와 이 벤트 를 수정 한 후에 파일 설명자 가 준비 되 기 를 기다 리 는 진정한 차단 입 니 다.
#include <sys/epoll.h>
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

epoll_wait () 는 epfd 를 기다 리 는 관심 목록 의 파일 과 이벤트 준 비 를 막 을 수 있 습 니 다. 시간 초과 시간 은 timeout 밀리초 입 니 다.시간 이 초과 되 지 않 아 파일 이 준비 되 지 않 으 면 준 비 된 파일 의 개 수 를 되 돌려 주 고 이벤트 에 정 보 를 저장 합 니 다.이 벤트 는 사용자 가 자체 적 으로 신청 한 배열 입 니 다. 내용 은 epoll 입 니 다.ctl () 시 설정 한 정보 입 니 다. 최대 요 소 는 maxevents 에서 지정 합 니 다. 즉, 한 번 에 최대 몇 개의 파일 이 준비 되 었 는 지 알려 줍 니 다.timeout 인 자 는 0 일 때 이 호출 이 막 히 지 않 고 조회 후 즉시 돌아 갑 니 다.위 - 1 시 는 시간 을 초과 하지 않 았 음 을 나타 낸다.오류 가 발생 했 을 때 - 1 을 되 돌려 주 고 errno 를 설정 하 며 시간 을 초과 하여 0 을 되 돌려 줍 니 다.
정확 한 용법 은 epollwait () 반환 후 반환 값 을 판단 합 니 다. 반환 값 이 0 이상 이면 이벤트 배열 을 옮 겨 다 니 며 이벤트 유형 과 fd 에 따라 처리 합 니 다.이 제 는 epoll () 과 select () / poll () 의 비교 우 위 를 볼 수 있 습 니 다. epoll () 은 파일 이 준 비 된 후에 우리 만 관심 을 가 져 야 할 파일 설명자 의 집합 을 제공 합 니 다. 뒤의 두 가지 처럼 모든 파일 설명 자 를 옮 겨 다 니 며 어떤 파일 이 준비 되 었 는 지 확인 하지 않 아 도 됩 니 다.다음 코드 는 표준 입력 에서 데이터 가 준비 되 고 읽 기 를 기다 리 는 것 을 보 여 줍 니 다.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/epoll.h>
#define MAX_EVENTS 3
int main (void)
{
    int nr_events, epfd;
    epfd = epoll_create(MAX_EVENTS);//         ,epoll     
    //             
    struct epoll_event events[MAX_EVENTS] = {};
    struct epoll_event evt;
    //            
    evt.events = EPOLLIN;
    evt.data.fd=STDIN_FILENO;

    int iRet = epoll_ctl(epfd, EPOLL_CTL_ADD, evt.data.fd, &evt);
    if(iRet == -1)
    {
        perror("epoll_ctl");
        return -1;
    }

    //           
    nr_events = epoll_wait(epfd, events, MAX_EVENTS, -1);
    if (nr_events < 0)
    {
        perror("epoll_wait");
        return -1;
    }
    for (int i = 0; i < nr_events; i++)
    {
        char temp[1024] = {0};
        iRet = read(events[i].data.fd, temp, sizeof(temp));
        printf("event=%ld on fd=%d,data:%s
"
, events[i].events, events[i].data.fd, temp); } }

파일 이 준비 되 기 를 기다 리 는 동안 신 호 를 받 았 습 니 다. epollwait () 는 오류 코드 EINTR 을 되 돌려 줍 니 다.이 때 는 epoll 을 다시 호출 하면 됩 니 다.wait (), 위의 프 리 젠 테 이 션 코드 는 특별한 처 리 를 하지 않 았 습 니 다.
또한 다 중 스 레 드 장면 에서 하나의 스 레 드 는 epoll 에 있 습 니 다.wait () 와 동시에 다른 스 레 드 에서 파일 설명 자 를 수정 할 수 있 습 니 다. 수정 은 즉시 유효 하 며 epoll / 에 영향 을 줄 수 있 습 니 다.wait()。테스트 코드 는 다음 과 같 습 니 다:
//    -lpthread,  pthread 
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/epoll.h>
#include <unistd.h>
#define MAX_EVENTS 3
void *thrd_func(void *arg);
int epfd;
int main()
{
    pthread_t tid;
    int *thread_ret = NULL;

    int nr_events;
    epfd = epoll_create(MAX_EVENTS);
    struct epoll_event events[MAX_EVENTS] = {};

    if (pthread_create(&tid,NULL,thrd_func,NULL)!=0)
    {
        printf("Create thread error!
"
); exit(1); } // // epoll nr_events = epoll_wait(epfd, events, MAX_EVENTS, -1); if (nr_events < 0) { perror("epoll_wait"); return -1; } // ,epoll_wait() printf("event=%ld on fd=%d,can write!
"
, events[0].events, events[0].data.fd); pthread_join(tid, (void**)&thread_ret ); return 0; } void *thrd_func(void *arg) { struct epoll_event evt; // , evt.events = EPOLLOUT; evt.data.fd=STDOUT_FILENO; sleep(3);// 3 printf("add fd!
"
); int iRet = epoll_ctl(epfd, EPOLL_CTL_ADD, evt.data.fd, &evt); if(iRet == -1) { perror("epoll_ctl"); } pthread_exit(NULL); }

좋은 웹페이지 즐겨찾기