728x90

2. Epoll

Event Poll: poll()과 select()를 개선한 형태

* select()

#include <sys/time.h>

#include <sys/types.h>

#include <unistd.h>

int select(int n,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,struct timeval *timeout);

FD_SET(int fd, fd_set *set); // fd를 set(검사대상)에 추가

FD_CLR(int fd, fd_set *set); // fd를 set에서 제거

FD_ZERO(fd_set *set);// set에 지정된 모든 대상 제거,select호출 전 항상 호출함

FD_ISSET(int fd, fd_set *set); //select()호출 후 fd가 사용 가능한지 확인 return bool

ex)

struct timeval tv;

fd_set readfds;

int ret;

FD_ZERO(&readfds);

FD_SET(STDIN_FILENO, &readfds);

tv.tv_sec = 0;

tv.tv_use = 500;

ret = select (STDIN_FILENO + 1, &readfds, NULL, NULL, &tv);

if(FD_ISSET(STDIN_FILENO, &readfds)){ /* 'fd' is readable without blocking! */ }

* poll()

#include <sys/poll.h>

int poll (struct pollfd *fds, unsigned int nfds, int timeout);

struct pollfd {

int fd; /* file descriptor */

short events; /* requested events to watch */

short revents; /* returned events witnessed */

};

ex)

struct pollfd fds[2];

int ret;

fds[0].fd = STDIN_FILENO;

fds[0].events = POLLIN;

fds[1].fd = STDOUT_FILENO;

fds[1].events = POLLOUT;

ret = poll(fds, 2, TIMEOUT);

if(fds[0].revents & POLLIN){ /* stdin is readable */ }

if(fds[0].revents & POLLOUT){ /* stdout is writable */ }

poll() vs select()

poll  select 
매개변수에 +1(FILENO+1)이 필요없다   
fd의 숫자가 큰 경우 select보다 효율적  fd_set값이 크면 비효율적이다. bitmask를 모두 검사하며 특히 bit가 분산된 경우 더욱 비효율적이다 
   매번 set을 초기화해야 한다.(FD_ZERO)
   이식성을 높이기 위해 timeout parameter(timeval)를 매번 초기화 해야함
 몇몇 UNIX에서는 poll을 지원하지 않는다  이식성이 높다
   microsecond단위까지는 timeout resolution이 더 좋다
 

*epoll()

2.6 Linux kernel 이후부터 사용 가능

select()/poll()은 호출될 때마다 fdset을 모두 확인하나 epoll은 실제 감시작업과 감시 등록작업을 분리하는 방법으로 이런 문제를 해결.

#include <sys/epoll.h>

int epoll_create(int size)

//size는 감시대상의 개수를 알려주는 힌트이며 정확한 수를 요구하지는 않는다.

return value : file descriptor or error(-1)

file descriptor는 poll이 끝난 다음 close()를 이용하여 닫아야 한다.

ex)

int epfd;

epfd = epoll_create(100);

if(epfd < 0) // errorclose(epfd);

int epoll_ctl(int epfd,

int op,

int fd,

struct epoll_event *event);

struct epoll_event{

__u32 events; /* events */

union {

void *ptr;

int fd;

__u32 u32;

--u64 u64;

}data;

};

op parameter

EPOLL_CTL_ADD : 감시대상에 fd 추가

EPOLL_CTL_DEL : 감시대상에서 fd 제거

EPOLL_CTL_MOD : 기존 등록된 fd의 event를 수정

ex)

struct epoll_event event;

int ret;

event.data.fd = fd;

event.events = EPOLLIN | EPOLLOUT;

ret = epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event);

if(ret) //ERROR

event.data.fd = fd;

event.events = EPOLLIN;

ret = epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &event);

ret = epoll_ctl(epfd, EPOLL_CTL_DEL, fd, &event);

** EPOLL_CTL_DEL을 사용할 때 event를 NULL로 보내면 2.6.9이전 버전에서 호환성이 맞지 않는다.

event 매개변수의 events필드에 EPOLLET값을 설정하면, fd에 대한 감시가 레벨트리거에서 에지트리거로 바뀐다. 에지트리거는 일반적으로 비차단 입출력을 활용하도록 다른 프로그래밍 접근방식을 요구하므로(만약 read를 요청하는 시점에 읽을 수 있는 상태라고 해도 write가 진행중이면 write가 끝날 때까지 기다린다) EAGAIN을 주의깊게 검사해야 한다.

#include <sys/epoll.h>

int epoll_wait (int epfd,

struct epoll_event *events,

int maxevents,

int timeout);

ex)

#define MAX_EVENTS64

struct epoll_event *events;

int nr_events, i, epfd;

events = malloc (sizeof(struct epoll_event) * MAX_EVENTS);

nr_events = epoll_wait (epfd, events, MAX_EVENTS, -1);

if(nr_events < 0) {

free(events);

return 1; //ERROR

}

for(i =0; i < nr_events; I++) {

//events[i].events마다 events[i].data.fd에 대한 작업 진행가능

}

free(events);

728x90

+ Recent posts