Recent Posts
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- Value too long for column
- python
- 겨울 부산
- table not found
- 깡돼후
- tolerated
- taint
- kotlin
- 헥사고날아키텍처 #육각형아키텍처 #유스케이스
- 오블완
- 달인막창
- terminal
- PytestPluginManager
- 코루틴 컨텍스트
- JanusGateway
- 개성국밥
- pytest
- JanusWebRTC
- k8s #kubernetes #쿠버네티스
- mp4fpsmod
- JanusWebRTCGateway
- PersistenceContext
- preemption #
- 자원부족
- 코루틴 빌더
- Spring Batch
- 티스토리챌린지
- VARCHAR (1)
- vfr video
- JanusWebRTCServer
Archives
너와 나의 스토리
[Unix] CH.7 Pipe, FIFO, I/O Multiplexing 본문
반응형
Pipes
- 가장 간단한 유닉스 interprocess communication(IPC) 메커니즘이다.
- 프로세스들끼리 파일 공유하는 방식(단방향으로)
- special file로 나타낸다
- 예) $ who | wc -l
$ who | wc -l
-> who 명령어로 인해 나오는 출력 값을 wc -l의 입력으로 넣음
즉, [who]에서 출력 값을 pipe에 write하고, [wc -l]는 pipe에 있는 데이터를 read 함
* [who], [wc -l], [wc -L] 단독 실행한 결과
pipe() system call
- First-in-first-out 방식
- 이러한 순서는 'lseek'로 대체 불가능하다 -> pipe에서 작동 안 함
- 두 가지 제약
- 단방향(half duplex) 통신
- pipe는 부모와 자식 사이에서 사용된다.
- 인자
- filedes[0]: read
- filedes[1]: write
- 프로세스가 파이프에 read 호출한 경우
- 파이프가 비어있지 않다면 - 즉시 read 리턴
- 파이프가 비어있다면 - 파이프에 무언가 적힐 때까지 read는 block 된다. (기다림)
- 프로세스가 파이프에 write 호출한 경우
- 파이프가 꽉 차있지 않다면 - 즉시 write 리턴
- 파이프가 꽉 차 있다면 - 파이프에 여유 공간이 생길 때까지 write는 block 됨
- 파이프의 한 쪽이 닫히는 경우
- write쪽이 닫히는 경우
- read는 모든 데이터를 읽은 후 EOF를 나타내기 위해 0을 리턴한다.
- read가 죽으면 write도 따라 죽음
- read쪽이 닫히는 경우
- SIGPIPE를 발생시킨다.
- 만약 시그널을 무시하거나 catch한 후 시그널 핸들러로부터 리턴하면, write()는 errno를 EPIPE로 설정하고 -1을 반환한다.
- write이 죽는닥고 read가 죽지는 않음 (read는 서버같은 느낌)
- write쪽이 닫히는 경우
example1
- parent, child 둘 다 pipe에 대한 read와 write이 다 열려있다.
- 만약 부모, 자식 프로세스가 동시에 write과 read를 진행한다면 충돌이 발생할 수 있다.
- 이를 피하기 위해서, 필요 없는 파일 디스크립터를 close 한다.
- 다음 예제의 경우, 자식이 종료되어도 부모의 write[4]이 남아 있기 때문에, read하기 위해서 파이프가 채워지기를 기다리며 영원히 block된다. (자식은 이미 죽어서 write을 못해주기 때문)
example2
- 자식의 read[3]와 부모의 write[4]을 닫음
- 자식이 죽으면 더 이상 write 해줄 프로세스가 없으므로 부모의 read가 블락되지 않는다.
Blocking & Non-blocking
- 시스템 콜은 호출자를 영원히 block할 수 있다.
- read는 특정 파일 타입(pipes, terminal devices, network devices)에 데이터가 존재하지 않으면 block된다.
- read할 게 없으면 blocking 됨 <- default 옵션
- write는 이러한 파일 타입에 의해 데이터에 즉시 접근할 수 없는 경우 block된다. (pipe에 남는 공간이 없음, network flow control, 등)
- write할 자리 없으면 blocking 됨
- 특정 파일 타입(FIFO)에 특정 조건이 발생할 때까지 block 됨
- read는 특정 파일 타입(pipes, terminal devices, network devices)에 데이터가 존재하지 않으면 block된다.
- 지정된 디스크립터에 대해 nonblocking I/O를 지정하는 두 가지 방법
- 만약 해당 디스크립터를 얻기 위해 open을 호출했다면 -> O_NONBLOCK 지정
- 이미 open된 디스크립터라면 -> O_NONBLOCK 파일 상태 플래그를 ON하기 위해 fcntl(옵션 변경 명령어)을 호출
int pfd[2];
if(pipe (pfd) == -1)
fatal ("pipe call");
if(fcntl(pfd[0],F_SETFL,O_NONBLOCK)==-1)
fatal ("fcntl call");
FIFO
- FIFP는 때때로 named pipes로 불린다.
- pipe는 이름을 지정할 수 있지만 fifo는 이름을 지정함
- 파이프는 공통의 조상이 파이프를 만들었을 때만 관련 프로세스 간에 사용할 수 있다.
- 그러나 FIFO를 사용하면 관련 없는 프로세스가 데이터를 교환할 수 있다.
- FIFO에는 소유자, 크기 및 접근 관련 권한도 있다.
- 다른 유닉스 파일과 마찬가지로 열거나 닫거나 삭제할 수 있다.
- 읽기 전용 또는 쓰기 전용으로 열어야 한다.
- FIFO는 반 이중이기 때문에 읽기-쓰기용으로 열려서는 안 된다.
- S_ISFIFO 매크로 테스트 할 수 있다.
channel이라는 이름의 FIFO를 만듦
P: mknod가 FIFO를 생성하도록 함
- FIFO는 first-in-first-out을 의미한다.
- pipe나 FIFO에 write할 때는 이미 존재하는 데이터 뒤에 쓰여지지만, read하는 경우에는 pipe나 FIFO의 처음부분이 리턴된다.
- PIPE나 FIFO에 lseek를 호출하면 ESPIPE 에러가 리턴된다.
mkfifo() system call
- 주어진 파일(pathname)을 FIFO 파일로 만들어 줌
- 인자:
- pathname: FIFO 파일 이름
- mode: permission mask
- Nonblocking flag(O_NONBLOCK) of open()
- O_NONBLOCK이 지정되지 않은 일반적인 경우
- read_only로 open: 다른 프로세스가 write을 위한 FIFO를 open할 때까지 block 됨
- write_only로 open: 다른 프로세그가 read를 위한 FIFO를 open할 때까지 block 됨
- O_NONBLOCK이 지정된 경우
- read_only로 open: 파일 디스크립터를 즉시 리턴
- write_only로 open: read를 위한 FIFO를 open한 프로세스가 없다면 errno를 ENXIO 설정하고 -1 리턴
- O_NONBLOCK이 지정되지 않은 일반적인 경우
example
- 오른쪽 중간 부분에서 open할 때, read만 할거면서 O_RDWR 지정한 이유?
- 이유1: 사소한 이유
- read_only로 open하는 경우 block되기 때문
- O_RDWR로 open하면 자기 자신의 write이 FIFO에 연결되어 있어 block 안 됨
- 이유2: 치명적인 이유
- read_only이면 for(;;)문에서 아무 일도 안하고 계속 루프를 돌게 된다
- RDWR을 지정하면 for(;;)문에서 read할 때, blocking되도록 해서 쓸데 없이 루프 돌지 않도록 한다.
- 이유1: 사소한 이유
I/O Multiplexing
- 우리가 하나의 디스크립터로부터 read하고, 다른 것으로부터 write할 때, 우리는 루프 안에서 blocking I/O를 사용할 수 있다.
while ((n = read(STDIN_FILENO, buf, BUFSIZ)) > 0)
if (write(STDOUT_FILENO, buf, n) != n)
err_sys("write error");
- 만약 우리가 두 개의 디스크립터로부터 read 해야 하는 경우
- 이런 상황을 처리할 다른 기술이 필요하다
- Non blocking I/O Model (polling)
- 루프 계속 돌기 때문에 -> CPU 시간 낭비
- multitasking system에서 피해야한다
- Multiplexing I/O Model
- select() or poll()
- Signal-Driven I/O Model (event)
- SIGIO
- Asynchronous I/O Model (event)
- SIGIO
- Non blocking I/O Model (polling)
select() system call
- select하기 위해 전달된 이 인자는 kernel에게 말한다.
- nfds: 우리가 관심있는 디스크립터가 무엇인지. 최대 fd값
- 만약 두 파일 디스크립터 3,4가 열렸다면, nfds는 반드시 5로 설정되어야한다.
- readfds: 주어진 디스크립터로부터 read를 원하는지
- 시스템에 의해 즉시 입력이 가능한지 확인(읽기가 block되지 않았는지 검사하기 위한 리스트, EOF 발생 검사)
- writefds: 주어진 디스크립터로부터 write을 원하는지
- 시스템에 의해 즉시 출력이 가능한지 확인(쓰기가 block되지 않았는지 검사하기 위한 리스트)
- exceptfds: 주어진 디스크립터에 대한 예외 조건에 관심이 있는지
- 예외가 있는지 검사하기 위한 리스트
- timeout: 우리가 얼마나 기다리고 싶은지
- select가 반환하기 전에 blocking될 수 있는 시간의 제한 값
- timeout==NULL이면 영원히 wait
- timeout==0이면 wait하지 않고 즉시 리턴
- readfds, writefds, execptfds
- 안 궁금하면 그냥 null pointer 넣어 놓으면 됨
- nfds: 우리가 관심있는 디스크립터가 무엇인지. 최대 fd값
- 0번 3번을 검사하겠다는 뜻
- 0번 검사했더니 read 안되는 경우 0으로 바꿈
- select()의 리턴 값
- return value: -1
- 에러 발생 ex) 시그널 잡힘
- 수정된 디스크립터 셋이 없음
- return value: 0
- 준비된 디스크립터가 없음 ex) timeout 값이 만료될 때
- 모든 디스크립터 셋이 0으로 설정됨
- return value: positive
- 디스크립터 넘버가 준비됨
- 모든 3개의 세트에 있는 준비된 디스크립터들의 합
- 만약 같은 디스크립터가 read, write 둘 다 준비되어 있다면, 리턴 값으로 2번 카운트된다.
- 세 개의 디스크립터 세트에 남아 있는 비트는 준비된 디스크립터에 해당하는 비트뿐이다.
- 디스크립터 넘버가 준비됨
- return value: -1
출처: [UNIX system programming]
반응형
'Unix > 이론' 카테고리의 다른 글
[Unix] CH.8 IPC (message queue, semaphores, shared memory) (0) | 2019.12.08 |
---|---|
[Unix] CH6. Signal and signal processing (0) | 2019.11.10 |
[Unix] CH3. File - ownership (0) | 2019.10.10 |
[Unix] CH2. File - system call, Standard I/O (0) | 2019.09.26 |
[Unix] Ch1. Basic concepts and terminology (0) | 2019.09.26 |
Comments