오늘도 밤이야

[UNIX] pipe(2) 더 잘 알고 활용하기 본문

UNIX

[UNIX] pipe(2) 더 잘 알고 활용하기

hyeonski 2021. 7. 10. 15:44

UNIX 환경에서의 대표적인 IPC(프로세스간 통신) 방법 중 하나인 pipe의 특징에 대해서 알아보자.

 

pipe는 단방향으로만 데이터를 전달할 수 있다

pipe는 커널 메모리를 파일로써 접근할 수 있게 해주어, pipe() 사용시 배열로 두 개의 file descriptor를 발급받는다. fd[0]은 input stream, fd[1]은 output stream으로, 부모 프로세스가 fd[1]에 write한 데이터를 자식 프로세스가 fd[0]으로 read 할 수 있다. 이때 반대의 경우는 사용이 불가능하다. 부모 프로세스가 write, 자식 프로세스가 read하는 상황에서 그 pipe를 유지한 채 자식프로세스가 fd[1]에 write할 수 없다.

 

이런 사용을 막기 위해 pipe 사용 시 각 프로세스에서 쓰지 않는 fd를 닫아야 한다. pipe를 만든 후, 프로세스 분기 시 각 프로세스는 사용하지 않을 fd를 먼저 close()한다. 부모에서 자식으로 데이터 전송 시 부모에서는 close(fd[0]), 자식에서는 close(fd[1])을 한다. 만약 close()하지 않을 경우, 전송한 데이터는 읽을 수 있으나 부모가 close() 하더라도 자식은 EOF를 받을 수 없다.

 

#include <unistd.h>
#include <stdio.h>

int main()
{
    int fd[2];
    pipe(fd);
    
    pid_t pid;
    pid = fork();
    if (pid < 0)
    	exit(1);
    else if (pid == 0) // child는 parent가 보낸 데이터를 read한다
    {
    	close(fd[1]); // 사용하지 않는 write fd는 close한다
        read(fd[0], buf, BUFFER_SIZE);
        ...
        
    }
    else // parent는 child에게 데이터를 write
    {
    	close(fd[0]); // 사용하지 않는 read fd는 close
        write(fd[1], data, DATA_SIZE);
        ...

    }
    ...
}

 

pipe에는 lseek이 적용되지 않는다

pipe는 먼저 write한 데이터가 먼저 read되는 First In - First Out의 특성을 가진다. 또한, pipe에 쌓인 데이터는 디스크에 저장되어 있는 것이 아닌 고정된 메모리 영역에 있고, 그 메모리의 가장 앞을 읽고 가장 끝에 데이터를 추가하는 원리이기 때문에 pipe에는 lseek을 적용할 수 없다. 애초 파일 포인터라는 개념이 적용되지 않는다고 볼 수 있다. 만약 pipe에 lseek을 호출할 경우, error을 리턴하고 errno를 ESPIPE로 세팅한다.

 

 

pipe의 크기는 정해져있다

pipe는 커널 메모리를 사용하기 때문에, 사용 가능한 capacity가 정해져있다. 구현에 따라 다르지만, 보통 65536 bytes의 크기를 가진다. pipe에 데이터가 가득 차 더 이상 write할 수 없는 상황에서 write를 호출할 경우 다음 두 가지 동작을 한다.

 

1. Blocking FD를 사용할 경우

pipe에 공간이 생겨 요청된 바이트 수만큼 write하기 전까지 write는 return되지 않는다. capacity가 65536 bytes인 pipe가 비어있는 상태에서 pipe에 100000 bytes만큼 write할 경우, 65536 bytes를 write하고, 나머지 34464 bytes를 write하기 전까지 block된다. 만약 write가 block되어있고, 다른 한 쪽에서 pipe를 read하여 공간이 생길 경우, read하여 생긴 공간만큼 추가적으로 write한다.

 

2. Non-Blocking FD를 사용할 경우

pipe에 write할 수 있는 만큼 write한 후 return된다. 만약 공간이 가득 차 1 byte도 write하지 못했다면, write는 -1을 리턴한다.

 

pipe에 read와 write가 동시에 일어나는 경우에는 write한 데이터를 실시간으로 read해주기 때문에 상관 없지만, write하는 동안 read 프로세스에서 다른 처리를 하고 있다면 write에서 멈추기 때문에 프로그램 작성 시 주의해야 한다. 예를 들어, blocking FD를 사용하는 자식 프로세스에서 1억 byte를 write하도록 했는데, 부모 프로세스에서는 read하지 않고 자식 프로세스의 종료를 wait() 한다면... 영원히 멈춰있을 것이다.

 

 

참고 자료

 

pipe(2) - Linux manual page

pipe(2) — Linux manual page PIPE(2) Linux Programmer's Manual PIPE(2) NAME         top pipe, pipe2 - create pipe SYNOPSIS         top #include int pipe(int pipefd[2]); #define _GNU_SOURCE /* See feature_test_macros(7) */ #include /* Definition of

man7.org

 

pipe(7) - Linux manual page

pipe(7) — Linux manual page PIPE(7) Linux Programmer's Manual PIPE(7) NAME         top pipe - overview of pipes and FIFOs DESCRIPTION         top Pipes and FIFOs (also known as named pipes) provide a unidirectional interprocess communication chan

man7.org

 

6.2.2 C로 파이프 만들기

리눅스 프로그래머를 위한 가이드 6.2.2 C로 파이프 만들기 (Creating Pipes in C) C 프로그래밍 언어로 파이프라인을 만드는 것은 간단한 쉘 예제보다는 많은 것을 포함한다. C로 간단한 파이프를 만들

www.xevious7.com

 

Ch.7 Pipe

interprocess communication using pipes Pipes - pipe는 UNIX system IPC의 가장 오래된 형태로써...

blog.naver.com

Comments