명령의 출력을 파일 (예 :)로 리디렉션하면 명령이 echo Hello > file
종료 된 직후 해당 파일에 해당 데이터가 포함됩니까? 또는 명령 엑시트와 파일에 기록 된 데이터 사이에 여전히 매우 작은 창이 있습니까? 명령이 종료 된 직후 파일을 읽으려고하지만 빈 파일을 읽고 싶지 않습니다.
답변
여러 계층의 버퍼 / 캐시가 있습니다.
-
CPU 캐시.
데이터는 바이트 단위로 조합되어 CPU 캐시에 저장됩니다. CPU 캐시가 가득 차서 한동안 데이터에 액세스하지 않은 경우 데이터가 포함 된 블록이 주 메모리에 기록 될 수 있습니다. 이들은 대부분 어플리케이션 프로그래머에게 숨겨져 있습니다.
-
공정 중 버퍼.
데이터가 수집되는 프로세스에는 일부 메모리 세트가 따로 있으므로, 비교적 비싸기 때문에 OS에 가능한 한 적은 요청을해야합니다. 이 프로세스는 데이터를 이러한 버퍼에 복사하며,이 버퍼는 다시 CPU 캐시에 의해 백업 될 수 있으므로 데이터가 주 메모리에 복사된다는 보장은 없습니다. 응용 프로그램은 이러한 버퍼를 명시 적으로 플러시해야합니다 (예 : fclose (3) 또는 fsync (3)). exit (3) 함수는 프로세스가 종료되기 전에이 작업을 수행하는 반면 _exit (2) 함수 는 그렇지 않으므로 사용자가 무엇인지 알고있는 경우에만 해당 함수에 대한 매뉴얼 페이지에 큰 경고가 표시됩니다. 하기.
-
커널 버퍼
그런 다음 OS는 자체 캐시를 유지하여 디스크로 전송해야하는 요청 수를 최소화합니다. 이 캐시는 특히 프로세스에 속하지 않으므로 거기에있는 데이터는 이미 완료된 프로세스에 속할 수 있으며 모든 액세스가 여기를 통과하므로 다음 프로그램은 여기에 도달하면 데이터를 보게됩니다. 커널은 시간이 있거나 명시 적으로 요청할 때이 데이터를 디스크에 기록합니다.
-
드라이브 캐시
디스크 드라이브 자체는 액세스 속도를 높이기 위해 캐시를 유지합니다. 이것들은 상당히 빠르게 작성되며, 캐시에 남아있는 데이터를 쓰고 명령이 완료되면보고하는 명령이 있습니다. OS는 종료시 전원을 끄기 전에 데이터가 기록되지 않은 상태로 남아 있지 않은지 확인하는 데 사용합니다.
응용 프로그램의 경우 커널 버퍼에 데이터를 등록하기에 충분합니다 (실제 데이터는이 시점에서 여전히 CPU 캐시에있을 수 있으며 주 메모리에 기록되지 않았을 수 있음). “echo”프로세스가 종료됩니다. 즉, 모든 프로세스 내 버퍼가 플러시되고 데이터가 OS로 전달되어야하며, 새 프로세스를 시작할 때 OS가 요청시 동일한 데이터를 다시 제공한다는 것을 의미합니다.
답변
응용 프로그램에 내부 캐시가 없으면 변경 내용이 파일에 즉시 기록됩니다. 귀하의 예와 동일합니다. 파일은 메모리의 논리 엔터티이며 즉시 업데이트됩니다. 파일에 대한 이후의 모든 작업에는 프로그램에서 변경 한 내용이 표시됩니다.
그러나 이것이 실제 디스크에 변경 사항이 기록되었음을 의미하지는 않습니다. 변경 사항은 OS 파일 시스템 캐시 또는 하드웨어 캐시에 남아있을 수 있습니다. 파일 시스템 버퍼를 플러시하려면 sync
명령을 사용하십시오 .
명령이 종료 된 직후 파일을 읽으려고하지만 빈 파일을 읽고 싶지 않습니다.
여기서 실제적인 문제가 발생하지 않아야합니다.
답변
프로세스가 종료되면 버퍼가 자동으로 디스크로 플러시됩니까?
일반적으로 대답은 ‘ 아니요’ 입니다.
명령에 따라 다릅니다. 다른 답변 언급으로, 경우 명령이 내부적으로 데이터를 버퍼링하지 않는, 모든 데이터는 때 명령 종료 사용할 수 있습니다.
그러나 전부는 아니더라도 대부분의 표준 I / O 라이브러리 는 기본적으로 어느 정도까지 버퍼 stdout을 수행 하며 응용 프로그램이 닫힐 때 버퍼의 자동 플러시에 대해 다른 보장을 제공합니다.
C는 정상적인 종료가 버퍼를 플러시 할 것을 보장합니다 . “정상 종료”는 exit
명시 적으로 또는에서 복귀하여 호출되는 것을 의미합니다 main
. 그러나 비정상적인 종료는이 호출을 피할 수 있으므로 플러시되지 않은 버퍼를 남겨 둡니다.
다음은 간단한 예입니다.
#include <signal.h>
#include <stdio.h>
int main() {
printf("test");
raise(SIGABRT);
}
이것을 컴파일하고 실행하면 반드시 stdout에 쓰여질 필요 test
는 없습니다 .
다른 프로그래밍 언어는 훨씬 적은 보증을 제공합니다. 예를 들어, Java 는 프로그램 종료시 자동 플러시 되지 않습니다 . 출력 버퍼에 종료되지 않은 행이 포함되어 있으면 System.out.flush()
명시 적으로 호출 되지 않는 한 손실 될 수 있습니다 .
즉, 질문 본문은 약간 다른 것을 요구합니다. 데이터가 파일 에 전혀 도착 하면 명령이 종료 된 직후에 수행해야합니다 (다른 답변에 설명 된주의 사항에 따라 다름 ).
답변
나는 아직이 문제를 충분히 다루는 질문이 없다고 생각한다.
명령이 종료 된 직후 파일을 읽으려고하지만 빈 파일을 읽고 싶지 않습니다.
다른 답변이 설명 하듯이, 잘 동작하는 프로그램은 프로세스가 정상적으로 종료되기 전에 내부 파일 버퍼를 플러시 합니다 . 이후 데이터는 영구 저장소에 쓰기 전에 커널 또는 하드웨어 버퍼에 남아있을 수 있습니다. 그러나 Linux의 파일 시스템 의미는 모든 프로세스가 내부 버퍼 1을 포함 하여 커널과 동일한 방식으로 파일의 내용을 볼 수 있도록 보장합니다 .
이는 일반적으로 파일 객체 당 최대 하나의 커널 내부 버퍼를 보유하고이 버퍼를 통과하기 위해 모든 파일 액세스를 요구하여 구현됩니다.
-
프로세스가 파일을 읽는 경우 요청 된 파일 부분이 현재 버퍼에있는 경우 커널은 버퍼 내용을 프로세스에 제공합니다. 그렇지 않은 경우 커널은 기본 저장 매체에서 데이터를 가져 와서 버퍼에 넣은 다음 이전 단계로 돌아갑니다.
-
프로세스가 파일에 쓰는 경우, 데이터는 먼저 해당 파일의 커널 내부 버퍼에 배치됩니다. 결국 버퍼 내용이 스토리지로 플러시됩니다. 평균적으로 읽기 액세스는 동일한 버퍼에서 이루어집니다 (위 참조).
1 최소한 일반 파일, 디렉토리 및 심볼릭 링크의 경우. FIFO와 소켓은 내용이 영구적으로 저장되지 않기 때문에 다른 문제입니다. 누가 요구하는지에 따라 내용이 달라지는 정규 파일의 특별한 경우가 있습니다. 예제는 procfs 및 sysfs의 파일입니다 ( /proc/self
심볼릭 링크를 읽는 프로세스의 프로세스 ID에 대한 심볼릭 링크 라고 생각 하십시오).
답변
C 런타임 라이브러리를 사용하여 일부 프로그램에서 명령을 실행한다고 가정하면 어느 시점 fclose
에서 열린 파일을 닫으려면 호출해야 합니다.
fclose
C 함수 매뉴얼 페이지 는 다음과 같이 말합니다.
참고 fclose ()는 C 라이브러리에서 제공하는 사용자 공간 버퍼 만 플러시합니다. 데이터가 디스크에 실제로 저장되도록하려면 커널 버퍼도 플러시해야합니다 (예 : sync (2) 또는 fsync (2)).
에 대한 매뉴얼 페이지 fflush
는 동일한 메모 를 가지고 있습니다. 에 대한 매뉴얼 페이지는 close
말합니다 :
닫기가 성공하더라도 커널이 쓰기를 연기함에 따라 데이터가 디스크에 성공적으로 저장되었다는 보장은 없습니다. 스트림이 닫힐 때 파일 시스템이 버퍼를 플러시하는 것은 일반적이지 않습니다. 데이터가 실제로 저장되어 있는지 확인해야하는 경우 fsync (2)를 사용하십시오. (이 시점에서는 디스크 하드웨어에 따라 다릅니다.)
드라이브와 동기화되지 않은 경우에도 다른 프로세스에서 데이터를 사용할 수 있습니다. 어쩌면 그것은 이미 당신에게 충분할 것입니다.
확실치 않은 경우 테스트를 작성하십시오.
답변
명령의 출력을 파일 (예 :)로 리디렉션하면 명령이
echo Hello > file
종료 된 직후 해당 파일에 해당 데이터가 포함됩니까?
예. 쉘은 출력 파일을 열고 echo
직접 출력합니다. 명령이 종료되면 완료됩니다.
또는 명령 엑시트와 파일에 기록 된 데이터 사이에 여전히 매우 작은 창이 있습니까?
데이터가 이미 미디어에 있는지 여부는 하드웨어 문제가 있거나 마운트 된 파일 시스템을 무시하고 법의학 소프트웨어로 라이브 파티션을 검사하는 경우에만 중요한 문제입니다.
명령이 종료 된 직후 파일을 읽으려고하지만 빈 파일을 읽고 싶지 않습니다.
걱정하지 마십시오. 커널은 파일을 여는 빈도와 관계없이 파일을 한 번만 볼 수 있습니다.
답변
일반적으로 커널 이 소유 한 모든 데이터 는 커널 기간별로 유지 보수 및 정리됩니다. 이러한 데이터에는와 같은 시스템 호출에 의해 커널 메모리로 전송 된 데이터가 포함됩니다 write(2)
.
그러나 응용 프로그램 (예 : C 라이브러리) 이이 위에서 버퍼링을 수행 하는 경우 커널은 전혀 알지 못하므로 정리를 보장하지 않습니다.
또한, 정리를위한 타이밍 보장 이 없다고 생각합니다 . 일반적으로 “최선의 노력”(읽기 : “초가있을 때”)으로 수행됩니다.