FIFO(명명된 파이프)는 일반 파이프(|)와 어떻게 다릅니까? 내가 아는 한위키피디아일반 파이프와 달리 FIFO 파이프는 프로세스가 끝난 후에도 "활성화"되며 나중에 삭제할 수 있습니다.
하지만 프로세스가 cat x | grep y
파이프( )를 포함하는 쉘 명령을 기반으로 하는 경우 이를 변수나 파일에 저장하면 "프로세스 후에도 활성 상태를 유지"할 수 있는데, 이 FIFO가 아닌가요?
또한 일반 파이프에도처음으로 얻은 표준 출력은 다른 명령의 표준 입력으로 사용됩니다., 그렇다면 선입선출 파이프라인도 아닌가요?
답변1
"명명된 파이프"는 실제로매우정확한 이름 - 파일 시스템에 이름이 있다는 점을 제외하면 일반 파이프와 같습니다.
파이프 - 사용되는 이름이 지정되지 않은 일반("익명") 파이프는 some-command | grep pattern
특별한 종류의 파일입니다. 나는 다른 파일과 마찬가지로 읽고 쓸 수 있는 파일을 언급하고 있습니다. Grep은 터미널 3이나 일반 파일이 아닌 파이프에서 읽는다는 사실에 전혀 신경 쓰지 않습니다.
기술적으로, 뒤에서 일어나는 일은 stdin, stdout 및 stderr이 각 명령 실행에 전달되는 세 개의 열린 파일(파일 설명자)이라는 것입니다. 파일 설명자(파일 읽기/쓰기 등의 모든 시스템 호출에 사용됨)는 단지 숫자일 뿐입니다. stdin, stdout 및 stderr은 파일 설명자 0, 1 및 2입니다. 따라서 쉘이 some-command | grep
이를 설정하면 다음을 수행합니다.
커널에서 익명 파이프를 요청합니다. 이름이 없으므로 일반 파일처럼 완료할 수 없습니다. 대신
open
두 개의 파일 설명자를 반환하는 or를 사용하여 완료합니다. ⁴pipe
pipe2
하위 프로세스를 포크하고(
fork()
상위 프로세스의 복사본을 만듭니다. 파이프의 양쪽이 여기에서 열립니다) 파이프의 쓰기 끝을 fd 1(stdout)에 복사합니다. 커널에는 파일 설명자 번호를 복사하기 위한 시스템 호출이 있습니다. yesdup2()
또는dup3()
. 그런 다음 읽기 측과 쓰기 측의 다른 복제본을 닫습니다. 마지막으로execve
실행 에 사용됩니다some-command
. 파이프가 fd 1이므로 stdoutsome-command
이 파이프입니다.다른 하위 프로세스의 포크입니다. 이번에는 파이프의 읽기 끝을 fd 0(stdin)에 복사하고 실행합니다
grep
. 따라서 grep은 파이프에서 stdin으로 읽습니다.그런 다음 두 아이가 나갈 때까지 기다리세요.
이 시점에서 커널은 파이프가 더 이상 열려 있지 않다는 것을 인식하고 이를 가비지 수집합니다. 이것이 실제로 파이프라인을 깨뜨리는 것입니다.
명명된 파이프는 단순히 파일 시스템에 넣어 익명 파이프에 이름을 부여합니다. 그래서 지금어느프로세스는 일반적인 시스템 호출을 사용하여 향후 언제든지 파이프의 파일 설명자를 얻을 수 있습니다 open
. 개념적으로 unlink
모든 판독기/기록기가 파이프를 닫고 파일 시스템에서 제거할 때까지 파이프는 파괴되지 않습니다. ²
그건 그렇고, 이것은 일반적으로 Unix에서 파일이 작동하는 방식입니다. unlink
(다음의 시스템 호출 rm
)은 단순히 파일 이름 중 하나를 삭제합니다. 모든 이름이 삭제되고 열려 있는 파일이 없을 때만 실제로 삭제됩니다. 다음은 이를 탐구하는 몇 가지 답변입니다.
- 하드 링크가 원본 링크와 동일한 공간을 차지하는 것처럼 보이는 이유는 무엇입니까?
- 로거가 삭제된 파일을 계속 기록하려면 어떻게 해야 합니까?
- 파일이 현재 사용 중이므로 Windows에서 불만을 표시하는 파일을 삭제/대체할 수 있도록 Linux에서는 어떤 차이점이 있습니까?
각주
- 기술적으로 이것은 사실이 아닐 수도 있습니다. 이해하면 일부 최적화가 가능할 수 있으며 실제 grep 구현은 종종 크게 최적화됩니다. 그러나 개념적으로는 상관하지 않습니다(실제로 grep을 직접 구현하는 것도 마찬가지입니다).
- 물론, 커널은 실제로 모든 데이터 구조를 메모리에 영원히 보관하는 것이 아니라 첫 번째 프로그램이 명명된 파이프를 열 때마다 이를 투명하게 다시 생성합니다(그런 다음 열리는 동안 해당 구조를 유지합니다). 그래서 그들은 오랫동안 주변에 있었던 것 같습니다.
- 터미널은 grep이 읽는 일반적인 장소는 아니지만 다른 터미널을 지정하지 않을 때 기본 표준 입력이 됩니다. 따라서
grep pattern
쉘에 입력 만 하면grep
터미널에서 읽혀집니다. 내가 생각할 수 있는 유일한 용도는 터미널에 무언가를 붙여넣으려는 경우입니다. - Linux에서는 익명 파이프가 실제로 특수 파일 시스템(pipefs)에 생성됩니다. 바라보다Linux에서 파이프가 작동하는 방식더 알아보기. 이는 Linux의 내부 구현 세부 사항입니다.
답변2
내 생각에 당신은 파이프의 셸 구문과 기본 Unix 시스템 프로그래밍을 혼동하고 있는 것 같습니다. 파이프/FIFO는 디스크에 저장되지 않지만 대신 커널의 버퍼를 통해 기록기에서 판독기로 데이터를 전달하는 파일 유형입니다.
open("/path/to/named_pipe", O_WRONLY);
시스템 호출(예: )을 수행 하거나 다음을 사용하여 작성기와 판독기에 액세스하는지 여부pipe(2)
새로운 익명 파이프를 생성하고 열린 파일 설명자를 읽기 및 쓰기 측에 반환합니다.
fstat(2)
sb.st_mode & S_IFMT == S_IFIFO
파일 설명자의 파이프는 어느 쪽이든 제공합니다 .
당신이 달릴 때foo | bar
:
- 내장되지 않은 명령의 경우 쉘은 평소와 같이 포크됩니다.
pipe(2)
그런 다음 익명 파이프의 입력과 출력이라는 두 개의 파일 설명자를 얻기 위해 시스템 호출이 이루어집니다 .- 그러다 포크된다다시.
- 어린이(
fork()
0을 반환함)- 파이프의 읽기 끝을 닫습니다(쓰기 fd를 열린 상태로 유지).
stdout
fd를 쓰도록 리디렉션합니다.dup2(pipefd[1], 1)
- 그래서
execve("/usr/bin/foo", ...)
- 부모(
fork()
0이 아닌 하위 PID를 반환함)- 파이프의 쓰기 끝을 닫습니다(읽기 fd를 열어 둡니다).
stdin
fd 읽기에서 리디렉션dup2(pipefd[0], 0)
- 그래서
execve("/usr/bin/bar", ...)
달리면 매우 유사한 상황에 직면하게 됩니다 foo > named_pipe & bar < named_pipe
.
명명된 파이프는 프로세스 간 파이프를 설정하기 위한 랑데부 지점입니다.
이 상황은 익명 tmp 파일과 명명된 파일의 경우와 유사합니다. open("/path/to/dir", O_TMPFILE | O_RDWR, S_IRUSR | S_IWUSR);
임시 파일을 만들 수 있습니다이름 없음( O_TMPFILE
), 마치 "/path/to/dir/tmpfile"
파일을 연 O_CREAT
다음 연결을 해제하고 삭제된 파일에 대한 파일 설명자를 남기는 것과 같습니다.
.linkat
O_TMPFILE
그러나 Linux에서는 특정 이름으로 생성된 후 삭제된 파일을 사용하여 이 작업을 수행할 수 없습니다.)