본문 바로가기

C Language

파이프 구조 및 여러개의 파이프 연결방법

 

파이프 닫기

파이프를 닫을 때 이렇게 하는 이유는 다음과 같습니다:


리소스 관리:
파일 디스크립터는 제한된 시스템 리소스입니다. 사용이 끝난 파이프를 닫음으로써 이 리소스를 해제하고 다른 프로세스나 같은 프로세스의 다른 부분에서 사용할 수 있게 합니다.

 

데이터 흐름 제어:
파이프의 읽기 끝(tube)과 쓰기 끝(tube)을 모두 닫음으로써, 파이프를 통한 데이터 전송이 완전히 종료되었음을 시스템에 알립니다.

 

EOF (End of File) 시그널링:
파이프의 쓰기 끝을 닫으면, 읽기 측에서 EOF를 감지할 수 있습니다. 이는 데이터 전송의 완료를 나타내는 중요한 신호입니다.

 

메모리 누수 방지:
열린 파일 디스크립터를 닫지 않으면 메모리 누수가 발생할 수 있습니다. 이 함수는 두 파이프 끝을 모두 닫아 이를 방지합니다.

 

에러 방지:
닫힌 파이프에 대한 추가적인 읽기나 쓰기 시도를 방지합니다. 이는 프로그램의 예측 가능성과 안정성을 높입니다.
이 함수는 파이프 사용이 완전히 끝났을 때 호출되어, 파이프와 관련된 모든 리소스를 정리하는 역할을 합니다.

 

파이프의 구조


tube: 읽기 전용 끝 (read end)
tube: 쓰기 전용 끝 (write end)

 

파이프는 단방향 통신 채널로, 데이터는 항상 쓰기 끝(tube)에서 읽기 끝(tube)으로 흐릅니다.

 

여러 명령어 연결 (파이프라인 확장)
여러 명령어를 파이프로 연결하려면 (예: cmd1 | cmd2 | cmd3), 각 명령어 사이에 별도의 파이프가 필요합니다.
예를 들어, 3개의 명령어를 연결하려면:
두 개의 파이프가 필요합니다: pipe1과 pipe2
프로세스 구조:
cmd1: stdout을 pipe1의 쓰기 끝으로 리다이렉트
cmd2: stdin을 pipe1의 읽기 끝으로, stdout을 pipe2의 쓰기 끝으로 리다이렉트
cmd3: stdin을 pipe2의 읽기 끝으로 리다이렉트
구현 예시
c
int pipe1[2], pipe2[2];
pid_t pid1, pid2, pid3;

pipe(pipe1);
pipe(pipe2);

// First child (cmd1)
if ((pid1 = fork()) == 0) {
    dup2(pipe1[1], STDOUT_FILENO);
    close(pipe1[0]);
    close(pipe1[1]);
    close(pipe2[0]);
    close(pipe2[1]);
    execve(cmd1, args1, env);
}

// Second child (cmd2)
if ((pid2 = fork()) == 0) {
    dup2(pipe1[0], STDIN_FILENO);
    dup2(pipe2[1], STDOUT_FILENO);
    close(pipe1[0]);
    close(pipe1[1]);
    close(pipe2[0]);
    close(pipe2[1]);
    execve(cmd2, args2, env);
}

// Third child (cmd3)
if ((pid3 = fork()) == 0) {
    dup2(pipe2[0], STDIN_FILENO);
    close(pipe1[0]);
    close(pipe1[1]);
    close(pipe2[0]);
    close(pipe2[1]);
    execve(cmd3, args3, env);
}

// Parent process
close(pipe1[0]);
close(pipe1[1]);
close(pipe2[0]);
close(pipe2[1]);

// Wait for children
waitpid(pid1, NULL, 0);
waitpid(pid2, NULL, 0);
waitpid(pid3, NULL, 0);
이 방식으로 필요한 만큼의 파이프와 프로세스를 생성하여 여러 명령어를 연결할 수 있습니다.