programing

새 라인이 형식 문자열에 없는 한 호출 후 인쇄가 플러시되지 않는 이유는?

prostudy 2022. 5. 8. 22:02
반응형

새 라인이 형식 문자열에 없는 한 호출 후 인쇄가 플러시되지 않는 이유는?

왜 그럴까?printf통화 후 뉴라인이 형식 문자열 내에 있지 않으면 플러시되지 않는지 여부이게 POSIX 행동인가?내가 어떻게 할 수 있었을까?printf매번 즉시 플러시하시겠습니까?

stdout스트림이 기본적으로 버퍼링되므로, 버퍼에 있는 내용이 새 라인에 도달한 후(또는 메시지가 표시될 때)에만 표시된다.즉시 인쇄할 수 있는 몇 가지 옵션:

  • 인쇄 대상stderr대신하여fprintf(stderr기본적으로 버퍼링되지 않음:

    fprintf(stderr, "I will be printed immediately");
    
  • 붉어지다stdout사용하기 위해 필요할 때마다fflush:

    printf("Buffered, will be flushed");
    fflush(stdout); // Will now print everything in the stdout buffer
    
  • 를 사용하여 stdout에서 버퍼링 사용 안 함setbuf:

    setbuf(stdout, NULL);
    
  • 또는 보다 유연한 사용:

    setvbuf(stdout, NULL, _IONBF, 0); 
    

아니, POSIX 동작이 아니라 ISO 동작이다(글쎄, POSIX 동작이지만 ISO에 부합하는 경우에만 해당).

표준 출력은 인터랙티브 장치를 참조하기 위해 감지될 수 있는 경우 라인이 버퍼링되고, 그렇지 않으면 완전히 버퍼링된다.그래서 그런 상황들이 있다.printf다음과 같은 새로운 회선을 보내더라도 플러싱되지 않는다.

myprog >myfile.txt

사용자와 상호 작용하는 경우 모든 행을 볼 수 있기 때문에 효율성이 타당하다.출력을 파일로 보내는 경우 다른 쪽 끝에는 사용자가 없을 가능성이 가장 높다(불가능하지는 않지만 파일을 미행하고 있을 수 있음).이제 사용자는 모든 문자를 보고 싶어하지만 그것에는 두 가지 문제가 있다고 주장할 수 있다.

첫번째는 효율적이지 않다는 것이다.두 번째는 원래 ANSI C 의무는 새로운 행동을 발명하기보다는 기존 행동을 주로 코드화하는 것이었고, 그러한 설계 결정은 ANSI가 프로세스를 시작하기 훨씬 전에 이루어졌다.요즘 ISO조차도 표준의 기존 규칙을 변경할 때 매우 조심스럽게 밟는다.

그것을 어떻게 처리할 것인가에 대해서는, 만약 당신이 한다면.fflush (stdout)즉시 보고자 하는 모든 출력 호출 후에, 그것이 문제를 해결할 것이다.

또는 다음을 사용할 수 있다.setvbuf 전 전stdout, 그것을 버퍼가 없는 것으로 설정하기 위해서 그리고 당신은 그것들 모두를 추가하는 것에 대해 걱정할 필요가 없을 것이다.fflush코드 줄:

setvbuf (stdout, NULL, _IONBF, BUFSIZ);

출력을 파일로 보낼 경우 성능에 상당한 영향을 미칠 수 있다는 점을 유념하십시오.또한 이에 대한 지원은 표준에 의해 보장되는 것이 아니라 구현에 정의된 것임을 명심하십시오.

ISO C99 섹션7.19.3/3관련 비트:

스트림이 버퍼링되지 않은 경우, 문자는 가능한 한 빨리 소스 또는 목적지에서 나타나도록 되어 있다.그렇지 않으면 문자가 누적되어 블록으로 호스트 환경으로 또는 호스트 환경에서 전송될 수 있다.

스트림이 완전히 버퍼링된 경우, 버퍼가 채워질 때 호스트 환경으로 또는 호스트 환경에서 블록으로 문자를 전송하도록 되어 있다.

스트림이 회선 버퍼링되는 경우, 문자는 새로운 회선 문자와 마주쳤을 때 블록으로 호스트 환경으로 또는 호스트 환경에서 전송되도록 되어 있다.

더욱이, 캐릭터는 버퍼 채우기, 버퍼링되지 않은 스트림에서 입력이 요청될 때 또는 호스트 환경에서 문자를 전송해야 하는 라인 버퍼링 스트림에서 입력이 요청될 때 호스트 환경으로 블록으로 전송되도록 되어 있다.

이러한 특성에 대한 지원은 구현이 정의되며, 다음을 통해 영향을 받을 수 있다.setbuf그리고setvbuf기능들

호출 즉시 플러시하려면 다음과 같이 하십시오.fflush(stdout)또는fflush(NULL)(NULL모든 것을 씻어내는 것을 의미한다.

그것은 아마도 효율적이고 만약 당신이 하나의 TTY에 글을 쓰는 여러 프로그램을 가지고 있다면, 당신은 이렇게 하면 당신은 인터레이스된 줄에 등장인물을 얻을 수 없기 때문일 것이다.따라서 프로그램 A와 B가 출력되는 경우 대개 다음과 같은 결과를 얻을 수 있다.

program A output
program B output
program B output
program A output
program B output

이건 냄새는 나지만, 그보다 낫다.

proprogrgraam m AB  ououtputputt
prproogrgram amB A  ououtputtput
program B output

새로운 라인에서는 플러싱이 보장되지 않으므로 플러싱이 중요한 경우 명시적으로 플러싱해야 한다는 점에 유의하십시오.

버퍼링에는 일반적으로 두 가지 레벨이 있다.

1. 커널 버퍼 캐시(읽기/쓰기가 빨라짐)

2. I/O 라이브러리의 버퍼링(시스템 호출 수 감소)

예를 들어 보자.fprintf and write().

전화할 때fprintf()파일에 직접 연결되지는 않는다.그것은 먼저 프로그램의 기억력에 있는 stdio buffer로 간다.거기서부터 쓰기 시스템 호출을 이용하여 커널 버퍼 캐시에 기록된다.따라서 I/O 버퍼를 건너뛰는 한 가지 방법은 쓰기()를 직접 사용하는 것이다.다른 방법으로는setbuff(stream,NULL)가 커널 버퍼링 모드를 버퍼링 없음으로 설정하고 데이터가 커널 버퍼에 직접 기록됨.데이터를 커널 버퍼로 강제 전환하려면 '\n'을 사용하면 되는데, '라인 버퍼링'의 기본 버퍼링 모드인 경우 I/O 버퍼 플러시를 한다.아니면 우리는 사용할 수 있다.fflush(FILE *stream).

지금 우리는 커널 버퍼에 있다.커널(/OS)은 디스크 액세스 시간을 최소화하고자 하므로 디스크 블록만 읽거나 쓰기를 원한다.그래서 ~할 때read()시스템 호출이며 직접 또는 를 통해 호출될 수 있음fscanf(), 커널은 디스크에서 디스크 블록을 읽고 버퍼에 저장한다.그 후에 데이터가 여기서 사용자 공간으로 복사된다.

마찬가지로fprintf()I/O 버퍼로부터 수신된 데이터는 커널에 의해 디스크에 기록된다.이렇게 하면 읽기() 쓰기 속도가 빨라진다.

이제 커널을 강제로 시작하려면write()하드웨어 컨트롤러에 의해 데이터 전송이 제어된 후에는 몇 가지 방법도 있다.우리는 사용할 수 있다.O_SYNC또는 쓰기 호출 중 유사한 플래그.아니면 다음과 같은 다른 기능을 사용할 수도 있다.fsync(),fdatasync(),sync()커널 버퍼에서 데이터를 사용할 수 있는 즉시 커널 쓰기가 시작되도록 한다.

stdout은 버퍼링되므로, 뉴라인이 인쇄된 후에만 출력된다.

즉시 출력을 얻으려면 다음 중 하나를 수행하십시오.

  1. stderr에 인쇄하십시오.
  2. 버퍼를 벗기지 않은 채 찌꺼기를 만들어라.

참고: Microsoft 런타임 라이브러리는 라인 버퍼링을 지원하지 않으므로printf("will print immediately to terminal"):

https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/setvbuf

사용하다setbuf(stdout, NULL);버퍼링을 비활성화하려면

대신 버퍼가 없는 stderr로 인쇄할 수 있다.아니면 당신이 원할 때 stdout을 씻어낼 수도 있다.아니면 stdout을 buffered로 설정할 수도 있다.

기본적으로 stdout은 라인 버퍼링되고 stderr은 버퍼링되지 않으며 파일이 버퍼링된다.

참조URL: https://stackoverflow.com/questions/1716296/why-does-printf-not-flush-after-the-call-unless-a-newline-is-in-the-format-strin

반응형