Search
Duplicate
🚦

[pipex] 파이프 이해하기

간단소개
pipex 과제에 필요한 pipe 이해하기
팔만코딩경 컨트리뷰터
ContributorNotionAccount
주제 / 분류
C
Operating System
42cursus
Scrap
태그
pipex
Operating System
9 more properties

PIPE 이해하기

PIPE?

프로세스간 통신 방법 중 하나
Anonymous PIPE, Named PIPE 로 분류할 수 있다.

Anonymous PIPE

부모 - 자식, 형제-형제 프로세스간 IPC 방법 중 하나
프로세스가 서로 명확한 경우에 사용할 수 있으며, Named PIPE에 비해 오버헤드가 작다.
An unnamed pipe  is accessible only by the process that created the pipe and its child processes. An unnamed pipe does not have to be opened before it can be used. It is a temporary file that lasts only until the last file descriptor that references it is closed. You can create an unnamed pipe by calling the pipe()  function. https://www.ibm.com/docs/en/zos/2.4.0?topic=operations-pipe-io
pipex 과제에서 활용하게 되는 파이프이다.
pipe() 함수를 통해 pipe 시스템 콜을 호출 할 수 있다.
파이프는 단방향으로 작동하여 한 프로세스는 Read 혹은 Write 만, 상대 프로세스는 Write 혹은 Read만 가능하다.
File descriptor 를 통해서 파이프에 연결되기 때문에, File descriptor를 통해 read(), write() 함수 등을 이용하게 된다.

Named PIPE

앞서 언급한 anonymous pipe의 경우에는 부모 - 자식, 형제-형제와 같이 통신하는 프로세스가 명확한 경우에만 사용할 수 있었다.
반면 Named PIPE의 경우에는 anonymous pipe의 기능에 더하여 통신 프로세스가 명확하지 않은 상황에서도 활용할 수 있다.
Named PIPE의 경우 PIPE typeFIFO 파일을 하나 생성하여 해당 파일을 통해 프로세스간에 통신을 이룬다.
anonymous PIPE의 경우 pipe() 를 통해서 파이프를 개설했다면, named PIPE의 경우 mkfifo() 함수를 통해서 named PIPE 파일을 생성한다.
해당 FIFO 파일을 open하여 read/write 작업을 수행한다. (half-duplex이기 때문에 두 프로세스간 full-duplex로 작동하기 위해서는 두 개의 파이프가 필요하다.)

부모 - 자식 프로세스간 PIPE 연결하기

Anonymous PIPE를 부모-자식 프로세스간 연결을 위해서는 두 프로세스 모두 파이프로 연결된 file descriptor에 대한 정보를 가지고 있어야한다.
Anonymous PIPE가 부모-자식, 형제-형제 프로세스간에만 사용할 수 있는 이유도 이것에 있다. PIPE를 open()을 통해서 fd를 가져올 수 없기 때문이다. 따라서, 서로 명확하지 않은 프로세스라면 PIPE로 통할 방법이 없다.
반면, 부모-자식, 형제-형제 프로세스의 관계에서는 fork()를 통해 메모리부터file table까지 그대로 복사를 한다. 결국, 연결하고자 하는 파이프의 fd 를 알 수 있고 이를 이용하여 파이프를 서로 연결할 수 있다.
부모로부터 자식으로 데이터가 전달되는 pipe를 만드는 과정은 아래와 같다.

파이프 만들기

부모와 자식 프로세스가 서로 파이프에 대한 fd 값들을 공유하기 위해서는 fork() 가 수행되기 전에 해당 정보를 담고 있어야한다. 따라서 fork() 이전에 먼저 pipe() 함수를 통해 파이프를 하나 만들어야한다. (양방향의 경우라면 두 개)
int fds[2] pipe(fds);
C
복사

fork

fork() 를 통해서 현재 프로세스를 fork() 한다. 이 때 두 프로세스의 상태는 다음과 같다.
int fds[2] pipe(fds); //// pid_t pid = fork(); ////
C
복사
목표로 하는 두 프로세스가 파이프에 모두 연결되었다. 이제 파이프를 원하는 방향으로 설정하자.

파이프 세팅하기

이제 파이프의 방향을 결정하면 된다. 이번 예제에서는 부모 프로세스에서 자식 프로세스로 데이터를 보낸다고 가정하자.
먼저, 부모 프로세스의 경우 pipe에 대해 read는 필요없다. 따라서 read에 해당되는 fds[0]을 닫아준다.
자식 프로세스일 경우 write를 사용하지 않는다. 따라서, write에 해당되는 fds[1] 를 닫자.
int fds[2] pipe(fds); pid_t pid = fork(); //// if (pid == 0) // CHILD PROCESS { close(fds[1]) // close write } else // PARENT PROCESS { close(fds[0]) // close read }
C
복사
결과적으로 두 프로세스간 파이프가 성공적으로 잘 연결이되었다.
fork() 이후, 자식 프로세스가 고아 상태가 되는 것을 방지하기 위해 wait() 함수를 잘 활용하도록 하자!

형제 프로세스간 PIPE연결하기

pipex 과제에서는 shell의 pipe와 동등하게 작동하도록 코드를 작성한다. 따라서, 실제로 작동하듯, 각 명령어는 각 프로세스를 할당받아 병렬적으로 실행된다.
즉, 병렬적으로 구성된다는 것은 부모 (1) : 자식 (N) 의 상태로 프로세스가 구성되어 각 자식 프로세스끼리 파이프가 연결된 상황을 말한다.
pipe를 활용하는 방법 자체를 동일하기 때문에 위 방법과 순서는 비슷하다.

파이프 만들기

우선, 두 프로세스가 통신을 하기 위해서는 파이프가 필요하다. 우선 파이프를 하나 먼저 개설한다.
int fds[2] pipe(fds);
C++
복사

fork() and fork()

우리의 목표는 부모 프로세스 → 자식 프로세스의 통신이 아닌, 자식 → 자식 간의 통신이다.
따라서, 파이프를 개설하고, 프로세스를 두 번 fork() 한다면, 동일한 파이프를 부모, 자식1, 자식2가 모두 하나의 파이프를 바라볼 수 있게 된다.
int fds[2] pipe(fds); pid_t pid = fork(); if (pid != 0) { pid = fork(); } else { do_some_process(); }
C++
복사

파이프 세팅하기

child process 1 → child process 2 간의 파이프를 형성하고 싶다고 가정하자.
parent process → child process 간의 통신은 불필요하므로, parent process에서는 pipe에 대해서 모두 close 해준다.
child process 1 의 경우 write 가 필요하므로, read 를 close한다.
child process 2 의 경우 read 가 필요하므로, write를 close한다.
int fds[2]; int child_num = 0; pipe(fds); pid_t pid = fork(); if (pid != 0) { child_num++; pid = fork(); close(fds[0]); close(fds[1]); } else { if (child_num == 0) close(fds[0]); if (child_num == 1) close(fds[1]); do_some_process(); }
C++
복사
그 결과 프로세스의 모습은 다음과 같이 된다.
만약, child process 2 → child process 3 간의 관계가 필요하다면, child process 2를 fork() 하기 전에 추가적인 파이프가 필요하다.

참고자료