프로세스가 종료되면 버퍼가 자동으로 디스크로 플러시됩니까?


21

명령의 출력을 파일 (예 :)로 리디렉션하면 명령이 echo Hello > file종료 된 직후 해당 파일에 해당 데이터가 포함됩니까? 또는 명령 엑시트와 파일에 기록 된 데이터 사이에 여전히 매우 작은 창이 있습니까? 명령이 종료 된 직후 파일을 읽으려고하지만 빈 파일을 읽고 싶지 않습니다.


1
아마도 명령을 바로 실행할 수 있지만 실제로 파일을 열고, 쓰고, 닫는 데 걸리는 시간은 하드 드라이브의 속도와 유형, 실행중인 프로그램 등에 따라 다릅니다.
freginold

주어진 예에서 '프로세스'란 무엇입니까? 인가 echo>없는 별도의 (단명) 프로세스? 그리고 echo유지 전의 출력은 어디에서 >실행됩니까?
oɔɯǝɹ

1
@ oɔɯǝɹ >는 쉘 리디렉션입니다. 프로그램이 명명 된 파일을 작성하기 위해 열어서 stdout을 셸이하는 파일로 대체 한 것과 동일합니다.
Dan D.

7
플러시 여부에 관계없이 file함유 물 을 제공하는 것이 OS의 책임이라고 생각합니다 Hello.
살만 A

1
프로그램이 시스템 A에서 실행 중이고 시스템 A의 파일 시스템이 네트워크를 통해 마운트 된 상태에서 시스템 B에서 파일을 읽는 경우 네트워크 파일 시스템 유형 및 마운트 설정에 따라 빈 파일을 읽을 수 있습니다. 따라서 해당 마운트에 대한 캐싱을 비활성화 할 수 있습니다.
pts

답변:


21

여러 계층의 버퍼 / 캐시가 있습니다.

  1. CPU 캐시.

    데이터는 바이트 단위로 조합되어 CPU 캐시에 저장됩니다. CPU 캐시가 가득 차서 한동안 데이터에 액세스하지 않은 경우 데이터가 포함 된 블록이 주 메모리에 기록 될 수 있습니다. 이들은 대부분 어플리케이션 프로그래머에게 숨겨져 있습니다.

  2. 공정 중 버퍼.

    데이터가 수집되는 프로세스에는 일부 메모리 세트가 따로 있으므로, 비교적 비싸기 때문에 OS에 가능한 한 적은 요청을해야합니다. 이 프로세스는 데이터를 이러한 버퍼에 복사하며,이 버퍼는 다시 CPU 캐시에 의해 백업 될 수 있으므로 데이터가 주 메모리에 복사된다는 보장은 없습니다. 응용 프로그램은 이러한 버퍼를 명시 적으로 플러시해야합니다 (예 : fclose (3) 또는 fsync (3)). exit (3) 함수는 프로세스가 종료되기 전에이 작업을 수행하는 반면 _exit (2) 함수 는 그렇지 않으므로 사용자가 무엇인지 알고있는 경우에만 해당 함수에 대한 매뉴얼 페이지에 큰 경고가 표시됩니다. 하기.

  3. 커널 버퍼

    그런 다음 OS는 자체 캐시를 유지하여 디스크로 전송해야하는 요청 수를 최소화합니다. 이 캐시는 특히 프로세스에 속하지 않으므로 거기에있는 데이터는 이미 완료된 프로세스에 속할 수 있으며 모든 액세스가 여기를 통과하므로 다음 프로그램은 여기에 도달하면 데이터를 보게됩니다. 커널은 시간이 있거나 명시 적으로 요청할 때이 데이터를 디스크에 기록합니다.

  4. 드라이브 캐시

    디스크 드라이브 자체는 액세스 속도를 높이기 위해 캐시를 유지합니다. 이것들은 상당히 빠르게 작성되며, 캐시에 남아있는 데이터를 쓰고 명령이 완료되면보고하는 명령이 있습니다. OS는 종료시 전원을 끄기 전에 데이터가 기록되지 않은 상태로 남아 있지 않은지 확인하는 데 사용합니다.

응용 프로그램의 경우 커널 버퍼에 데이터를 등록하기에 충분합니다 (실제 데이터는이 시점에서 여전히 CPU 캐시에있을 수 있으며 주 메모리에 기록되지 않았을 수 있음). "echo"프로세스가 종료됩니다. 즉, 모든 프로세스 내 버퍼가 플러시되고 데이터가 OS로 전달되어야하며, 새 프로세스를 시작할 때 OS가 요청시 동일한 데이터를 다시 제공한다는 것을 의미합니다.


7
CPU 캐싱을 고려하면 나와 관련이없는 것 같습니다. 그것은 불필요한 세부 수준입니다. 하드 디스크 플래터 또는 ssd 메모리의 비트를 나타내는 일부 물리적 수량이 뒤집어 질 때까지 모든 세부 사항을 거치게됩니다.
mvw

3
실제로 CPU 캐시는 상당히 직교합니다.
Simon Richter

2
더 중요한 것은 CPU 캐시가 코어간에 일관성이 있기 때문에 완전히 그림에서 벗어난 것입니다. x86에서는 DMA와 일관성이 있으며 (x86에는 총 저장 순서 메모리 순서 모드가 있음) 메모리를 읽을 수있는 모든 항목은 메모리 순서의 글로벌 순서로 해당 주소에 가장 최근에 저장된 데이터를 볼 수 있습니다. (CPU 코어는 상점 큐에서 상점 전달로 인해 글로벌로 표시되기 전에도 자체 상점을 볼 수 있습니다). 캐시 일관성 DMA가없는 x86 이외의 플랫폼에서 Linux 커널은 캐시가 DMA보다 먼저 해당 주소로 플러시되도록합니다.
Peter Cordes

1
"이들은 대부분 애플리케이션 프로그래머에게 숨겨져 있습니다." 왜 "대부분"입니까? 나는 임베디드 개발자이며 부트 로더를 제외하고 ( "애플리케이션"이 아님) CPU 캐시를 완전히 무시합니다. CPU 캐시의 영향으로 응용 프로그램 개발자가 영향을받을 수 있다고 생각하지 않습니다.
Sam

1
일부 CPU에서는 @Sam 캐시 누락 / 적중이 추측 실행과 함께 읽기 액세스 제한을 우회 할 수 있습니다. 아마도 이것이 대답이 말한 것입니까?
John Dvorak

22

응용 프로그램에 내부 캐시가 없으면 변경 내용이 파일에 즉시 기록됩니다. 귀하의 예와 동일합니다. 파일은 메모리의 논리 엔터티이며 즉시 업데이트됩니다. 파일에 대한 이후의 모든 작업에는 프로그램에서 변경 한 내용이 표시됩니다.

그러나 이것이 실제 디스크에 변경 사항이 기록되었음을 의미하지는 않습니다. 변경 사항은 OS 파일 시스템 캐시 또는 하드웨어 캐시에 남아있을 수 있습니다. 파일 시스템 버퍼를 플러시하려면 sync명령을 사용하십시오 .

명령이 종료 된 직후 파일을 읽으려고하지만 빈 파일을 읽고 싶지 않습니다.

여기서 실제적인 문제가 발생하지 않아야합니다.


1
“애플리케이션에 내부 캐시가없는 경우”– 매우 큰“if”: 대부분의 I / O 라이브러리 구현은 기본적으로 버퍼 stdout을 사용합니다. 예를 들어 C 표준은 종료시 stdout 버퍼를 플러시해야합니다 (그러나 exit적어도 암시 적으로 호출 되지 않으면 잠재적으로 아닙니다 ). 다른 라이브러리 / 언어 (예 : Java!)는 더 적은 보증을 제공합니다.
Konrad Rudolph

리디렉션 프리미티브 (즉, 내 질문의 명령)로 제한하면 어떻게됩니까? 내부 캐시가 없습니다. 그렇습니까?
Eric

@ 에릭 아니, 당신은 괜찮을거야.
mtak

10
이 답변을 받았는지 잘 모르겠습니다. 문제는 "프로세스가 종료 될 때"에 관한 것입니다. 내부 쓰기 캐시가있는 모든 응용 프로그램은 프로세스 종료시 디스크로 플러시합니다. 이 캐시는 여기서 중요하지 않습니다.
MSalters

2
또한 내부 버퍼는 종료시 플러시되거나 존재에서 사라집니다. 따라서 내부 버퍼가 플러시되지 않더라도 대기 시간에 관계없이 내용을 관찰 할 수 없습니다.
WorldSEnder

21

프로세스가 종료되면 버퍼가 자동으로 디스크로 플러시됩니까?

일반적으로 대답은 ' 아니요' 입니다.

명령에 따라 다릅니다. 다른 답변 언급으로, 경우 명령이 내부적으로 데이터를 버퍼링하지 않는, 모든 데이터는 때 명령 종료 사용할 수 있습니다.

그러나 전부는 아니더라도 대부분의 표준 I / O 라이브러리 기본적으로 어느 정도까지 버퍼 stdout을 수행 하며 응용 프로그램이 닫힐 때 버퍼의 자동 플러시에 대해 다른 보장을 제공합니다.

C는 정상적인 종료가 버퍼를 플러시 할 것을 보장합니다 . "정상 종료"는 exit명시 적으로 또는에서 복귀하여 호출되는 것을 의미합니다 main. 그러나 비정상적인 종료는이 호출을 피할 수 있으므로 플러시되지 않은 버퍼를 남겨 둡니다.

다음은 간단한 예입니다.

#include <signal.h>
#include <stdio.h>

int main() {
    printf("test");
    raise(SIGABRT);
}

이것을 컴파일하고 실행하면 반드시 stdout에 쓰여질 필요 test없습니다 .

다른 프로그래밍 언어는 훨씬 적은 보증을 제공합니다. 예를 들어, Java 는 프로그램 종료시 자동 플러시 되지 않습니다 . 출력 버퍼에 종료되지 않은 행이 포함되어 있으면 System.out.flush()명시 적으로 호출 되지 않는 한 손실 될 수 있습니다 .

즉, 질문 본문은 약간 다른 것을 요구합니다. 데이터가 파일 에 전혀 도착 하면 명령이 종료 된 직후에 수행해야합니다 (다른 답변에 설명 된주의 사항에 따라 다름 ).


7
또한 명령 줄 도구가 디버그 로그와 같이 파일과 stdout 또는 stderr에 쓰는 중 비정상 종료가 발생했으며 사용자가 파이프를 헤드 이하로 수행 한 다음 'q'를 입력하여 덜 종료했습니다. 명령 행 도구가 SIGPIPE를 처리하지 않은 경우 디스크 파일이 항상 완전히 플러시되지는 않습니다.
Zan Lynx

+1,하지만 "그렇게 즉시해야 명령 종료"입니다 꽤 잘 : 어떤 write()또는 pwrite()시스템 호출이 일어날 전에 프로세스가 종료 및의하는 파일 변경이 표시 될 때. 그래서 마지막 파일 변화는 확실히 전에 최신 즉시-전에, 프로세스 종료. mmap(MAP_SHARED)파일이 있더라도 모든 파일 변경이 발생하기 전에 프로세스 종료가 발생하는 것을 관찰 할 수있는 방법이 없다고 생각합니다.
Peter Cordes

9

나는 아직이 문제를 충분히 다루는 질문이 없다고 생각한다.

명령이 종료 된 직후 파일을 읽으려고하지만 빈 파일을 읽고 싶지 않습니다.

다른 답변이 설명 하듯이, 잘 동작하는 프로그램은 프로세스가 정상적으로 종료되기 전에 내부 파일 버퍼를 플러시 합니다 . 이후 데이터는 영구 저장소에 쓰기 전에 커널 또는 하드웨어 버퍼에 남아있을 수 있습니다. 그러나 Linux의 파일 시스템 의미는 모든 프로세스가 내부 버퍼 1을 포함 하여 커널과 동일한 방식으로 파일의 내용을 볼 수 있도록 보장합니다 .

이는 일반적으로 파일 객체 당 최대 하나의 커널 내부 버퍼를 보유하고이 버퍼를 통과하기 위해 모든 파일 액세스를 요구하여 구현됩니다.

  • 프로세스가 파일을 읽는 경우 요청 된 파일 부분이 현재 버퍼에있는 경우 커널은 버퍼 내용을 프로세스에 제공합니다. 그렇지 않은 경우 커널은 기본 저장 매체에서 데이터를 가져 와서 버퍼에 넣은 다음 이전 단계로 돌아갑니다.

  • 프로세스가 파일에 쓰는 경우, 데이터는 먼저 해당 파일의 커널 내부 버퍼에 배치됩니다. 결국 버퍼 내용이 스토리지로 플러시됩니다. 평균적으로 읽기 액세스는 동일한 버퍼에서 이루어집니다 (위 참조).


1 최소한 일반 파일, 디렉토리 및 심볼릭 링크의 경우. FIFO와 소켓은 내용이 영구적으로 저장되지 않기 때문에 다른 문제입니다. 누가 요구하는지에 따라 내용이 달라지는 정규 파일의 특별한 경우가 있습니다. 예제는 procfs 및 sysfs의 파일입니다 ( /proc/self심볼릭 링크를 읽는 프로세스의 프로세스 ID에 대한 심볼릭 링크 라고 생각 하십시오).


2
엄밀히 말하면, 이것을 보장하는 것은 Linux의 파일 시스템 의미가 아니라 POSIX 의미입니다. 특히 BSD는 macOS 및 Windows와 똑같이 동작합니다 (Windows는 POSIX 의미론을 따르는 몇 안되는 경우 중 하나임). 또한 아무도 mmap()O_DIRECT를 사용 하여 이상한 일을하지 않는다고 가정합니다. 이로 인해 디스크와 페이지 캐시가 동기화되지 않을 수 있습니다 (그러나 프로세스가 종료되는 순간을 해결할 것입니다).
Austin Hemmelgarn

2
@AustinHemmelgarn : 엄밀히 말하면 Linux는 Unix (System V) 응용 프로그램을 지원하도록 설계되었고 나중에 System V에 대한 많은 개념을 기반으로하는 POSIX를 지원하도록 만들어 졌기 때문에 둘 다 맞습니다.
David Foerster

5

C 런타임 라이브러리를 사용하여 일부 프로그램에서 명령을 실행한다고 가정하면 어느 시점 fclose에서 열린 파일을 닫으려면 호출해야 합니다.

fcloseC 함수 매뉴얼 페이지 는 다음과 같이 말합니다.

참고 fclose ()는 C 라이브러리에서 제공하는 사용자 공간 버퍼 만 플러시합니다. 데이터가 디스크에 실제로 저장되도록하려면 커널 버퍼도 플러시해야합니다 (예 : sync (2) 또는 fsync (2)).

에 대한 매뉴얼 페이지 fflush는 동일한 메모 를 가지고 있습니다. 에 대한 매뉴얼 페이지는 close말합니다 :

닫기가 성공하더라도 커널이 쓰기를 연기함에 따라 데이터가 디스크에 성공적으로 저장되었다는 보장은 없습니다. 스트림이 닫힐 때 파일 시스템이 버퍼를 플러시하는 것은 일반적이지 않습니다. 데이터가 실제로 저장되어 있는지 확인해야하는 경우 fsync (2)를 사용하십시오. (이 시점에서는 디스크 하드웨어에 따라 다릅니다.)

드라이브와 동기화되지 않은 경우에도 다른 프로세스에서 데이터를 사용할 수 있습니다. 어쩌면 그것은 이미 당신에게 충분할 것입니다.

확실치 않은 경우 테스트를 작성하십시오.


2
C 여부에 관계없이 모든 것은 close()syscall을 사용하여 파일 설명자를 닫습니다.
Attie

@Attie : 당신은하지 않습니다 필요close(오류를 검사하지 않는 해키 프로그램) 종료하기 전에 파일; 커널은 그것들을 정리하고 close프로세스가 끝난 후에 효과적으로 호출 합니다. 종료 시스템 호출과 직접 반대로 fclose버퍼링 된 stdio 스트림 이 필요 하거나 libc가이를 수행 exit(3)하도록하십시오.
Peter Cordes

확실치 않은 경우 테스트를 작성하십시오. 경쟁 조건을 감지하는 데 나쁜 조언입니다. 하나의 하드웨어에서 실행되는 하나의 커널에서 테스트하면 해당 시스템의 테스트에서 생성 된 소프트웨어 조건에서 경쟁이 발생할 수 없거나 감지하기가 너무 드물다는 것을 알 수 있습니다. 그러나 그 행동이되어 있는지 여부를 알 수 없습니다 되어 모든 파일 시스템, 커널에 걸쳐 안전하고, 모든 하드웨어 (예 : 파워). 즉, 당신이 의존하는 보증이 구현 세부 사항인지 또는 미래 지향적 미래 보장 보증인지 알 수 없습니다! (이 경우에 해당합니다.)
Peter Cordes

상황에 따라 다릅니다. 쉘 스크립트를 실행하려는 일부 사람들은이 조언에 도움이 될 수 있습니다. OS 커널에서 작업하는 소프트웨어 엔지니어, 인텔의 마이크로 코드 업데이트에서 작업하는 사람들 또는 ISS의 일부 시스템에서 작업하는 일부 여자와 같이보다 고급이지만 덜 가능성있는 환경에 대한 일반적인 솔루션으로 사용되지 않았습니다.
mvw

3

명령의 출력을 파일 (예 :)로 리디렉션하면 명령이 echo Hello > file종료 된 직후 해당 파일에 해당 데이터가 포함됩니까?

예. 쉘은 출력 파일을 열고 echo직접 출력합니다. 명령이 종료되면 완료됩니다.

또는 명령 엑시트와 파일에 기록 된 데이터 사이에 여전히 매우 작은 창이 있습니까?

데이터가 이미 미디어에 있는지 여부는 하드웨어 문제가 있거나 마운트 된 파일 시스템을 무시하고 법의학 소프트웨어로 라이브 파티션을 검사하는 경우에만 중요한 문제입니다.

명령이 종료 된 직후 파일을 읽으려고하지만 빈 파일을 읽고 싶지 않습니다.

걱정하지 마십시오. 커널은 파일을 여는 빈도와 관계없이 파일을 한 번만 볼 수 있습니다.


"커널은 파일의 하나 개의보기 유지":하지 마찬가지 mmap(MAP_SHARED): (스레드 또는 다른 프로세스에 의해) 파일의 읽기와 mmaped 영역으로 저장 일관성없는합니다. 이것이 msync(2)존재하는 이유 입니다. 최소한 그것은 맨 페이지가 경고 한 것입니다. 구현에 따라 Linux는 실제로 페이지 캐시에서 실제 페이지를 매핑 할 수 있습니다.이 경우 기본적으로 일관성이 있다고 생각합니다 (모듈로 메모리 순서). 어쨌든, 그것은 여전히 ​​전에 일어납니다 _exit(2).
Peter Cordes

2

일반적으로 커널소유 한 모든 데이터 는 커널 기간별로 유지 보수 및 정리됩니다. 이러한 데이터에는와 같은 시스템 호출에 의해 커널 메모리로 전송 된 데이터가 포함됩니다 write(2).

그러나 응용 프로그램 (예 : C 라이브러리) 이이 위에서 버퍼링을 수행 하는 경우 커널은 전혀 알지 못하므로 정리를 보장하지 않습니다.

또한, 정리를위한 타이밍 보장 이 없다고 생각합니다 . 일반적으로 "최선의 노력"(읽기 : "초가있을 때")으로 수행됩니다.


waitpid()정리가 전혀 발생하지 않으면 부모 프로세스가 리턴 되기 전에 정리 / 버퍼 플러싱이 발생한다는 보장이 있습니다. 즉, 다른 프로세스는 해당 프로세스에서 파일을 수정하기 전에 프로세스 종료가 발생하는 것을 직접 관찰 할 수 없습니다 . (NFS 캐싱은 호스트간에 완벽하게 일관성이 없기 때문에 NFS 파일 타임 스탬프를 통한 간접 관찰을 배제하기 위해 "직접적으로"말했습니다.)
Peter Cordes

@PeterCordes : "유지"와 반대로 "정리"의 의미에 따라 다릅니다. 나에게 "유지"는 "일관된 견해를 제공한다"(귀하가 언급 한 보증이 있음)이고 "정리"는 타이밍 보증이 없다고 생각되는 "디스크에 플러시"입니다.
Mehrdad

아시다시피, 당신은 질문의 "디스크에 플러시"부분에 대답하고 있습니다. "깨끗한 i / o 캐시 / 버퍼 메모리 정리"라는 의미에서 "정리" 오른쪽, 어떤 타이밍 보장되지는 사용하지 않는 fsync/ fdatasync리눅스에 버퍼 다시 쓰기가 이후에 시작됩니다 있지만 /proc/sys/vm/dirty_writeback_centisecs(다른 I / O 트래픽을 지연하지 않은 경우) 두 번째 백분, 그 procfs의 디렉토리에 다양한 튜너 블도 일을 영향 (예를 들면 방법 쓰기 백을하기 전에 버퍼가 커지도록 크게합니다).
Peter Cordes

2

또는 명령 엑시트와 파일에 기록 된 데이터 사이에 여전히 매우 작은 창이 있습니까?

아닙니다.

명령이 종료 된 직후 파일을 읽으려고하지만 빈 파일을 읽고 싶지 않습니다.

명령이 종료 된 직후 파일의 최종 내용을 읽을 수 있으며 빈 파일을 읽지 않습니다. (C 및 C ++에서 wait , waitpid , wait3 또는 wait4 시스템 호출을 사용하여 프로그램이 종료 될 때까지 기다렸다가 파일을 읽습니다. 쉘, 다른 프로그래밍 언어 또는 라이브러리 (예 : C 라이브러리)를 사용하는 경우 호출 시스템 또는 Java 프로세스 클래스), 이미 이러한 시스템 호출 중 하나를 사용하고있을 것입니다.)

다른 답변과 의견이 지적했듯이 내부 출력 버퍼를 플러시하지 않고 프로그램이 종료 된 경우 (예 : _exit , 중단 또는 치명적인 신호 또는 정상적으로 종료되는 Java 프로그램). 그러나이 시점에서이 작업을 수행 할 수있는 작업이 없습니다. 유출되지 않은 데이터는 영구적으로 손실되므로 추가 대기로 복구 할 수 없습니다.


0

또 다른 불필요한 답변을 추가하여 죄송하지만 대부분 질문 제목의 빨간 청어에 초점을 맞추는 것 같습니다. 그러나 내가 알 수있는 한, 문제는 전혀 버퍼링에 관한 것이 아니라 다음과 같습니다.

명령 출력을 파일 (예 : echo Hello> 파일)로 리디렉션하면 명령이 종료 된 직후에 해당 파일에 해당 데이터가 포함됩니까?

예, 무조건. "|"와 함께 설명하고있는 ">"사용법 "<"는 Unix 및 Linux 세계가 기반으로하는 파이프 기반 처리 모델입니다. 모든 Linux 설치에서이 동작에 따라 수천 개의 스크립트가 아니라면 수백 개의 스크립트가 있습니다.

디자인마다 원하는대로 작동하며, 경합 조건이 가장 적더라도 수십 년 전에 수정되었을 것입니다.


불행히도 이것은 불필요합니다. 응답 중 두 가지만이 주로 비 휘발성 스토리지에 데이터를 커밋하는 청각에 중점을 둡니다. 명확한 설명은 @pts의 답변 과 다른 몇 가지를 참조하십시오 . 파일 수정은 종료 전에 발생하거나 전혀 발생하지 않습니다.
Peter Cordes
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.