일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 랜덤출력
- HTML
- SQL
- 프로그래밍
- 함수중복
- call by referance
- 객체지향프로그래밍
- 친구함수
- 코딩
- 연산자재정의
- freiend선언
- 생성자호출
- 자바스크립트
- new연산자
- 제네릭 함수
- 웹개발
- C언어
- 멤버접근허용
- freiend클래스
- jQuery
- friend함수
- 함수표현식
- 테이블
- 자바스크립트라이브러리
- time()
- JS
- 데이터베이스
- this객체
- C++
- react
- Today
- Total
Programming Storytelling
다중 입출력 방식 select()/poll() 본문
##다중 입출력이란?##
"애플리케이션이 여러개의 파일 디스크립터를 동시에 블록하고 그중 하나라도 블록되지 않고 읽고 쓸 준지가 되면 알려주는 기능을 제공한다."
다중 입출력 방식은 어떠한 설계방식을 따르는데 그 설계 과정에 대하여 살펴보도록 하자.
1.다중 입출력:파일 디스크립터 중 하나가 입출력이 가능할 때 알려준다.
2.준비가 됐나?준비된 파일 디스크립터가 없다면 하나 이상의 파일 디스크립터가 준비될 때까지 잠든다.
3.깨어나기,어떤 파일 디스크립터가 준비됐나?
4.블록하지 않고 모든 파일 디스크립터가 입출력을 준비하도록 관리한다.
5.1번으로 돌아가서 다시 시작한다.
다중 입출력 방식인 select()는 시스템 콜은 동기화된 다중 입출력 메커니즘을 제공하는데
select()를 활용하는 예제를 보면서 이를 이해 해 보자.
include<stdio.h>
int select (int n,
fd_set *readfds
fd_set * *writefds,
fd_set * *excepttfds,
struct timeval *timeout);
FD_CLR(int fd,fd_set *set);
FD_ISSET(int fd,fd_set *set);
FD_SET(int fd,fd_set *set);
fd_zero(fd_set *set);
select()호출은 파일 디스크립터가 입출력을 수행할 준비가 되거나 옵션으로 정해진 시간이 경과할 때까지만 블록된다.
이제 위의 예제 코드를 분석 해 보도록 하겠다.
fd_set *readfds ,fd_set * *writefds, fd_set * *excepttfds는 각각 읽기가 가능한지,쓰기가 가능한지,예외가 발생했거나 대역을 넘어서는 데이터가 존재하는지 감시한다.
첫번째 인자인 n은 파일 디스크립터 집합에서 가장 큰 파일 디스크립터 숫자에 1을 더한 값이다. 따라서 select()를 호출하려면 파일 디스크립터에서 가장 큰 값이 무엇인지 알아내서 이 값에 1을 더해 첫 번째 인자에 넘겨야 한다.
time out 인자는 timeval구조체를 가리키는 포인터이며 이 구조체는 아래와 같이 정의되어있다.
#include<stdio.h>
struct timeval {
long tv_sec;
long tcc_usec;
};
이 인자가 NULL이 아니면 select()호출은 입출력이 준비된 파일 디스크립터가 없을 경우에도 tv_sec초와 tv_usec마이크로 초 이후에 반환한다.
timeout에 설정된 두 값이 모두 0이면 호출은 즉시 반환되며 호출하는 시점에서 대기 중인 이벤트를 알려주지만 그다음 이벤트를 기다리지 않는다.
select()에서 사용하는 파일 디스크립터 집합은 직접 조작하지 않고 매크로를 사용해서 관리한다.이렇게 하면 각 유닉스 시스템에 맞춰 집합을 구현할 수 있다,하지만 대다스의 시스템에서는 파일 디스크립터 집합을 비트 배열 처럼 간단한 방식으로 구현하고 있다.
FD_ZERO는 지정한 집합내의 모든 파일 디스크립터를 제거한다.이 매크로는 항상 select()를 호출하기 전에 사용해야 한다.
FD_SET은 주어진 집합에 파일 디스크립터를 추가하고
FD_CLR 매크로는 주어진 집합에서 파일 디스크립터를 하나 제거한다.
제대로 설계된 코드라면 FD_CLR를 사용할 일이 절대 없으며 실제로도 사용되는 경우가 드물다.
FD_ISSET매크로는 파일 디스크립터가 주어진 집합에 존재하는지 검사한다.
파일 디스크립터가 집합에 들어 있으면 0이 아닌 정수를 반환하며 들어 있지 않다면 0을 반환한다.
if (FD_ISSET(fd,&readfds))
/*fd에서 즉시 값을 읽을 수 있다! */
select()의 반환값과 에러 코드
EBADF | 집합에 제공된 파일 디스크립터가 유효하지 않다. |
EINTR | 대기 중에 시그널이 발생했으며 다시 호출할 수 있다. |
EINVAL | 인자 n이 음수이거나 timeout값이 유효하지 않다. |
ENOMEM | 요청을 처리하기 위한 메모리가 충분하지 않다. |
pselect()와 select()에는 다음 세 가지 차이점이 있다.
1.pselect()는 timeout 인자로 timeval구조체 대신timespec구조체를 사용한다, timespec구조체는 초,마이크로 초가아니라 초,나노 초 조합을 사용하므로 이론적으로는 더 짧은 시간 동안 잠들 수 있다. 하지만 실제로는 둘 다 마이크로 초도 확실히 지원하지 못한다.
2.peselct()는 timeout인자를 변경하지 않기 때문에 잇달은 호출과정에서 timeout인자를 계속 초기화 해야 할 필요가 없다.
3.select()시스템 콜은 sigmask인자를 받지 않는다. 이 인자를 NULL로 설정하면 pselect()는 select()와 동일하게 동작한다.
poll()시스템 콜은 시스템 v에서 제공하는 다중 입출력 방식이다.poll()은 select()의 몇 가지 결점을 보완한다,하지만 그럼에도 불구하고 여전히 습관이나 이식성의 이유로 select()를 더 많이 사용하고 있다.
poll() 시스템 콜이 사용된 실습코드를 함께 보도록 하자.
#include <stdio.h>
#include <unistd.h>
#include <poll.h>
#define TIMEOUT 5
int main(){
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 *1000);
if (ret == -1) {
perror ("poll");
return 1;
}
if(!ret) {
printf("%d seconds elapsed. \n", TIMEOUT);
return 0;
}
if (fds[0].revents & POLLIN)
printf("stdin is readable\n");
if(fds[1].revents &POLLOUT)
printf("stdout is writeable\n");
return 0;
##poll()과 select()비교##
비록 같은 작업을 수행하지만 poll()시스템 콜은 다음과 같은 몇 가지 이유 때문에 select()보다 훨씬 유용하다.
1.poll()은 가장 높은 파일 디스크립터 값에 1을 인자로 전달할 필요가 없다.
2.poll()은 파일 디스크립터 숫자가 큰 경우에 좀 더 효율적으로 동작한다. select()로 값이 900인 단일 파일 디스크립터를 감시한다고 할 때, 커널은 매번 전달된 파일 디스크립터 집합에서 900번째 비트까지 일일이 검사해야 한다.
3.select90의 파일 디스크립터 집합은 크기가 정해져 있으므로 트레이드 오프가 발생한다.집합의 크기가 작으면 select(
)가 감시할 최대 파일 디스크립터가 연속적이지않고 드문드문 흩어져 있을 경우에는 특히 심각하다. *poll()을 사용하면 딱 맞는 크기의 배열 하나만 사용하면 된다. 하나만 검사할 경우에는 구조체 하나만 넘기면 끝난다.
3.select()를 사용하면 파일 디스크립터 집합을 반환하는 시점에서 재구성되므로 잇따른 호출과정에서 매번 파일 디스크립터 집합을 다시 초기화해야 한다. poll()시스템 콜은 입력(events 필드)과 출력(revents 필드)을 분리하므로 변경 없이 배열을 재사용할 수 있다.
4.select()의 timeout인자는 반환하게 되면 미정의 상태가 된다.따라서 코드의 이식성을 높이려면 timeout인자를 다시 초기화해야한다.하지만pselect()를 사용할 경우에는 이런 문제가 없다.
'C언어' 카테고리의 다른 글
c 표준정의와 관련 에러 설명 (0) | 2019.04.17 |
---|---|
지역변수와 전역변수 알아보기 (0) | 2019.04.15 |
문자열 관련 함수에 대하여 (0) | 2019.04.15 |