파이프
파이프는 프로세스에게 노출되는 작은 커널 버퍼로, 읽기 및 쓰기를 위한 두 개의 파일 디스크립터로 구성됩니다. 한쪽 끝에 데이터를 쓰면 해당 데이터가 파이프의 다른 쪽 끝에서 읽을 수 있게 됩니다. 파이프는 프로세스 간 통신을 제공합니다.
다음 예시 코드는 표준 입력을 파이프의 읽기 끝에 연결하여 프로그램 wc를 실행합니다.
int p[2];
char *argv[2];
argv[0] = "wc";
argv[1] = 0;
pipe(p);
if(fork() == 0) {
close();
dup(p[0]);
close(p[0]);
close(p[1]);
exec("/bin/wc", argv);
} else {
close(p[0]);
write(p[1], "hello world\n", 12);
close(p[1]);
}
프로그램은 pipe를 호출하여 새로운 파이프를 생성하고 읽기 및 쓰기 파일 디스크립터를 배열 p에 기록합니다. fork 이후, 부모와 자식 모두 파이프를 가리키는 파일 디스크립터를 가지게 됩니다. 자식 프로세스는 close 및 dup를 호출하여 파일 디스크립터 0이 파이프의 읽기 끝을 가리키도록 만들고, p의 파일 디스크립터를 닫은 후에 exec를 호출하여 wc를 실행합니다. wc가 표준 입력에서 읽을 때, 파이프에서 읽습니다. 부모 프로세스는 파이프의 읽기 측을 닫고, 파이프에 쓰고, 그런 다음 쓰기 측을 닫습니다.
파이프에서 읽기 작업(read)이 수행될 때, 데이터가 쓰여질 때까지 기다립니다. 또는 쓰기 끝을 가리키는 모든 파일 디스크립터가 닫힐 때까지 기다립니다. 후자의 경우, 읽기는 데이터 파일의 끝에 도달한 것과 마찬가지로 0을 반환합니다. 읽기가 새로운 데이터가 도착할 수 없을 때까지 차단되는 사실은 아래의 wc를 실행하기 전에 자식 프로세스가 파이프의 쓰기 끝을 닫는 것이 중요한 이유 중 하나입니다. 왜냐하면 만약 wc 중 하나의 파일 디스크립터가 파이프의 쓰기 끝을 가리키면, wc는 파일의 끝을 볼 수 없기 때문입니다.
여기서 wc란 무엇일까?
wc는 표준 입력에서 데이터를 읽고 그 데이터를 처리함
이 명령어는 텍스트 파일이나 표준 입력으로부터 문자, 단어 및 줄의 수를 세는 데 사용됩니다.
예시 : wc filename.txt
xv6 셸은 위의 코드와 유사한 방식으로 grep fork sh.c | wc -l과 같은 파이프라인을 구현합니다. 자식 프로세스는 파이프를 생성하여 파이프라인의 왼쪽 끝과 오른쪽 끝을 연결합니다. 그런 다음, 왼쪽 끝과 오른쪽 끝에 대해 fork 및 runcmd를 호출하고 두 프로세스가 완료될 때까지 기다립니다. 파이프라인의 오른쪽 끝은 파이프를 포함하는 명령일 수 있으며 (예: a | b | c), 이 경우 b와 c를 위해 두 개의 새로운 자식 프로세스가 생성됩니다. 따라서 셸은 프로세스 트리를 생성할 수 있습니다. 이 트리의 잎은 명령이고 내부 노드는 왼쪽과 오른쪽 자식이 완료될 때까지 기다리는 프로세스입니다.
원칙적으로, 내부 노드가 파이프라인의 왼쪽 끝을 실행하도록 할 수 있지만, 이렇게 하는 것은 구현을 복잡하게 만들 수 있습니다. 다음 수정 사항만으로도 충분합니다: sh.c를 수정하여 내부 프로세스에서 fork하지 않고 runcmd(p->left)를 실행하십시오. 그러나 예를 들어 echo hi | wc 는 출력을 생성하지 않을 것입니다. 왜냐하면 runcmd에서 echo hi가 종료되면 내부 프로세스가 종료되어 오른쪽 끝의 파이프를 실행할 fork를 호출하지 않기 때문입니다. 이러한 잘못된 동작은 내부 프로세스에서 exit를 호출하지 않음으로 수정할 수 있습니다. 그러나 이러한 수정은 코드를 복잡하게 만듭니다. 이제 runcmd가 내부 프로세스인지 여부를 알아야 합니다. runcmd(p->right)에 대해 fork하지 않는 경우에도 복잡성이 발생합니다. 예를 들어, 그러한 수정만으로는 sleep 10 | echo hi 가 즉시 "hi"를 출력하고 10초 후에 출력하는 것이 아니라 즉시 "hi"를 출력합니다. 이는 echo가 즉시 실행되고 종료되어 sleep이 완료될 때까지 기다리지 않기 때문입니다. sh.c의 목표가 가능한 한 간단하게 유지하는 것이기 때문에 내부 프로세스 생성을 피하려고하지 않습니다. 파이프는 일시적인 파일보다 강력해 보이지 않을 수 있습니다.
echo hello world | wc
파이프 없이 구현될 수 있습니다.
echo hello world >/tmp/xyz; wc </tmp/xyz
파이프는 임시 파일보다 적어도 네 가지 이점이 있습니다. 첫째, 파이프는 자동으로 자신을 정리합니다. 반면에 파일 리다이렉션의 경우, 쉘은 작업이 완료되면 /tmp/xyz를 제거하는 데 주의해야 합니다. 둘째, 파이프는 임의로 긴 데이터 스트림을 전달할 수 있지만, 파일 리다이렉션은 모든 데이터를 저장할만큼 충분한 디스크 공간이 필요합니다. 셋째, 파이프는 파이프 라인 단계의 병렬 실행을 허용하지만, 파일 방식은 두 번째 프로그램이 시작되기 전에 첫 번째 프로그램이 완료되어야 합니다. 네 번째로, 프로세스 간 통신을 구현하는 경우, 파이프의 블로킹 읽기와 쓰기가 파일의 논블로킹 의미론보다 효율적입니다.
블로킹 읽기와 쓰기는 입출력 작업이 완료될 때까지 프로세스가 대기하는 방식
논블로킹 의미론은 입출력 작업이 바로 완료되지 않더라도 대기하지 않고 다른 작업을 수행하는 방식
'xv6-book' 카테고리의 다른 글
xv6-book (1.5 Real world) (2) | 2024.02.06 |
---|---|
xv6-book (1.4 File system) (1) | 2024.02.05 |
xv6-book (1.2 I/O and File descriptors) (0) | 2024.02.04 |
xv6-book (Ch1.1-Processes and memory) (0) | 2024.01.30 |
xv6-book (Ch1-Operating system interfaces) (0) | 2024.01.29 |