[Linux/C] 다중 입출력 - select()
다중 입출력 - select()
'다중 입출력'은 프로그램(단일 스레드)에서 여러 개의 파일을 작업하고자 할 때 사용할 수 있는 메커니즘입니다. 사실 '단일 스레드'에서 여러 개의 파일을 작업하고자 할 때 사용할 수 있는 다른 방법으로는 '논블록(Non-Block) 입출력'을 사용하는 방법도 있긴 합니다만, '논블록(Non-Block) 입출력'은 프로그래밍 작업이 까다롭습니다. 이제부터 설명할 'select'는 '블록/비동기적 입출력'에서의 '다중 입출력' 모델입니다.
A, B, C, D 4개의 파일을 다루는 작업을 하고싶다고 가정해볼때 다음과 같은 시나리오를 생각해볼 수 있습니다.
1. A 파일에 대한 작업을 합니다.
2. A 파일에 대한 작업을 마칩니다.
3. B 파일에 대한 작업을 합니다.
4. B 파일에 대한 작업을 하다가 프로그램이 '블록(Block)' 상태에 빠집니다.
파일에 대한 작업 중 '블록(Block)' 상태가 되는 이유야 다양하겠지만 대표적으로 read() 함수를 호출했는데 읽을 파일이 없다면 프로그램은 읽을 내용이 생길 때까지 '블록(Block)'됩니다. 그럼 위의 상황에서 '블록' 없이 어떻게 4개의 파일에 대한 작업을 정상적으로 실행할 수 있을까요? 답은 간단합니다. A, B, C, D 파일을 순서대로 작업할게 아니라 작업할 준비가된 파일에 대해서만 작업을 하면됩니다. 이러한 생각이 시초가 되어 최초로 탄생한 함수가 'select' 시스템콜입니다.
#include <sys/select.h> int select(int n, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, 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()'는 해당 파일 디스크립터가 입출력을 수행할 준비가 되거나 마지막 매개변수인 timeout 변수에 정해진 시간이 경과할 때까지만 '블록'됩니다. '감시 대상 파일 디스크립터'는 3가지 집합으로 나뉘어 각각 다른 '이벤트'를 기다립니다.
readfds: '읽기'가 가능한지 감시합니다. (블록되지 않고 read() 작업이 가능한지)
writefds: '쓰기'가 가능한지 감시합니다. (블록되지 않고 write() 작업이 가능한지)
exceptfds: 예외가 발생했거나 대역을 넘어서는 데이터(소켓)가 존재하는지 감시합니다.
만약 select() 함수의 매개변수로 NULL을 넘기면 해당 이벤트는 감시하지 않습니다. select() 시스템콜의 예제를 살펴보겠습니다.
#include <stdio.h> #include <sys/time.h> #include <sys/types.h> #include <unistd.h> #define TIMEOUT 5 #define BUF_LEN 1024 int main() { struct timeval tv; fd_set readfds; int ret; // 표준 입력에서 입력을 기다리기 위한 준비를 합니다. FD_ZERO(&readfds); FD_SET(STDIN_FILENO, &readfds); // select가 5초 동안 기다리도록 timeval 구조체를 설정합니다. tv.tv_sec = TIMEOUT; tv.tv_usec = 0; // select() 시스템콜을 이용해 입력을 기다립니다. ret = select(STDIN_FILENO + 1, &readfds, NULL, NULL, &tv); if (ret == -1) { perror("select"); return 1; } else if (!ret){ printf("%d seconds elapsed.\n", TIMEOUT); return 0; } // select() 시스템콜이 양수를 반환했다면 '블록(block)'없이 즉시 읽기가 가능합니다. if (FD_ISSET(STDIN_FILENO, &readfds)) { char buf[BUF_LEN + 1]; int len; // '블록(block)'없이 읽기가 가능합니다. len = read(STDIN_FILENO, buf, BUF_LEN); if (len == -1) return 1; if (len) { buf[len] = '\0'; printf("read: %s\n", buf); } return 0; } }
'Operating System > Linux' 카테고리의 다른 글
[Linux/C] 메모리 맵 파일 (0) | 2019.06.05 |
---|---|
[Linux/C] 버퍼 입출력 - 표준 입출력 라이브러리 (0) | 2019.06.04 |
[Linux/OS] 가상 파일 시스템 (0) | 2019.06.04 |
[Linux/C] 다중 입출력 - poll() (0) | 2019.06.03 |
[Linux/C] 파일 입출력 (0) | 2019.05.22 |
댓글
이 글 공유하기
다른 글
-
[Linux/C] 버퍼 입출력 - 표준 입출력 라이브러리
[Linux/C] 버퍼 입출력 - 표준 입출력 라이브러리
2019.06.04 -
[Linux/OS] 가상 파일 시스템
[Linux/OS] 가상 파일 시스템
2019.06.04 -
[Linux/C] 다중 입출력 - poll()
[Linux/C] 다중 입출력 - poll()
2019.06.03 -
[Linux/C] 파일 입출력
[Linux/C] 파일 입출력
2019.05.22
댓글을 사용할 수 없습니다.