programing

printf anomaly 뒤에 "printf"가 표시됩니다

projobs 2022. 8. 27. 23:02
반응형

printf anomaly 뒤에 "printf"가 표시됩니다

OS: Linux, 언어: 순수 C

저는 일반적으로 C프로그래밍을 배우고 특별한 경우 UNIX에서 C프로그래밍을 배우고 있습니다.

나는 (나에게) 이상한 행동을 감지했다.printf()사용 후 기능하다fork()불러.

코드

#include <stdio.h>
#include <system.h>

int main()
{
    int pid;
    printf( "Hello, my pid is %d", getpid() );

    pid = fork();
    if( pid == 0 )
    {
            printf( "\nI was forked! :D" );
            sleep( 3 );
    }
    else
    {
            waitpid( pid, NULL, 0 );
            printf( "\n%d was forked!", pid );
    }
    return 0;
}

산출량

Hello, my pid is 1111
I was forked! :DHello, my pid is 1111
2222 was forked!

두 번째 "Hello" 문자열이 자녀의 출력에서 발생한 이유는 무엇입니까?

네, 시작할 때 부모가 인쇄한 것과 똑같습니다.pid.

근데! 만약에 저희가...\n각 문자열의 말미에 표시되는 문자의 출력은 다음과 같습니다.

#include <stdio.h>
#include <system.h>

int main()
{
    int pid;
    printf( "Hello, my pid is %d\n", getpid() ); // SIC!!

    pid = fork();
    if( pid == 0 )
    {
            printf( "I was forked! :D" ); // removed the '\n', no matter
            sleep( 3 );
    }
    else
    {
            waitpid( pid, NULL, 0 );
            printf( "\n%d was forked!", pid );
    }
    return 0;
}

출력:

Hello, my pid is 1111
I was forked! :D
2222 was forked!

왜 이렇게 될까요?올바른 행동입니까, 아니면 버그입니까?

주의:<system.h>비표준 헤더로 대체했습니다.<unistd.h>코드가 깔끔하게 컴파일 되어 있습니다.

프로그램의 출력이 터미널(화면)로 전송되면 라인 버퍼링됩니다.프로그램의 출력이 파이프로 전송되면 완전히 버퍼링됩니다.표준 C 기능으로 버퍼링 모드를 제어할 수 있습니다.setvbuf()및 그_IOFBF(완전 버퍼링),_IOLBF(회선 버퍼링) 및_IONBF(버퍼링 없음) 모드

예를 들어, 프로그램의 출력을 다음과 같이 배선함으로써 개정된 프로그램에서 이를 입증할 수 있습니다.cat. 마지막 줄에 줄바꿈틀림 없이printf()문자열, 이중 정보를 볼 수 있습니다.터미널로 직접 보내시면 한 가지 정보만 보실 수 있습니다.

그 이야기의 교훈은 전화할 때 조심하는 것이다.fflush(0);포킹하기 전에 모든 I/O 버퍼를 비웁니다.


요청에 따른 줄별 분석(괄호 등 제거 - 마크업 편집기에 의해 선행 공백 제거):

  1. printf( "Hello, my pid is %d", getpid() );
  2. pid = fork();
  3. if( pid == 0 )
  4. printf( "\nI was forked! :D" );
  5. sleep( 3 );
  6. else
  7. waitpid( pid, NULL, 0 );
  8. printf( "\n%d was forked!", pid );

분석 내용:

  1. 표준 출력을 위해 버퍼에 "Hello, my pid is 1234"를 복사합니다.말미에 새로운 회선이 없고 출력이 라인 버퍼 모드(또는 풀 버퍼 모드)로 실행되고 있기 때문에 단말기에는 아무것도 표시되지 않습니다.
  2. stdout 버퍼에서 정확히 동일한 재료를 사용하는 두 가지 공정을 제공합니다.
  3. 아이는 가지고 있다pid == 0행 4와 5를 실행합니다.부모의 값은 0이 아닙니다.pid(두 프로세스 간의 몇 가지 차이 중 하나 - 값 반환:getpid()그리고.getppid()2개 더 있음)
  4. 새 행을 추가하고 "I were forked!D"를 자식의 출력 버퍼에 연결합니다.출력의 첫 번째 행이 단말기에 표시되며, 출력은 라인 버퍼가 되므로 나머지 행은 버퍼에 저장됩니다.
  5. 모든 것이 3초 동안 멈춘다.그 후 아이는 메인 끝의 리턴을 통해 정상적으로 퇴장합니다.이 시점에서, stdout 버퍼내의 잔존 데이터가 플래시 됩니다.줄 바꿈이 없으므로 출력 위치는 줄 바꿈 끝에 남습니다.
  6. 부모가 여기로 와요.
  7. 부모는 아이가 죽을 때까지 기다린다.
  8. 부모가 새로운 행을 추가하고 "1345 was forked!" 가 출력 버퍼에 추가됩니다.새 행은 하위 행에 의해 생성된 불완전한 행 뒤에 'Hello' 메시지를 출력으로 플러시합니다.

이제 메인 끝의 반환을 통해 부모가 정상적으로 종료되고 나머지 데이터는 플러시됩니다.끝에 아직 새로운 행이 없기 때문에 커서의 위치는 느낌표 뒤에 있고 셸 프롬프트는 같은 행에 표시됩니다.

내가 보는 건

Osiris-2 JL: ./xx
Hello, my pid is 37290
I was forked! :DHello, my pid is 37290
37291 was forked!Osiris-2 JL: 
Osiris-2 JL: 

PID 번호는 다르지만 전체적인 외관은 선명합니다.의 끝에 줄바꿈 추가printf()스테이트먼트(표준 프랙티스가 되는 것은 매우 빠르게)는 출력을 크게 변경합니다.

#include <stdio.h>
#include <unistd.h>

int main()
{
    int pid;
    printf( "Hello, my pid is %d\n", getpid() );

    pid = fork();
    if( pid == 0 )
        printf( "I was forked! :D %d\n", getpid() );
    else
    {
        waitpid( pid, NULL, 0 );
        printf( "%d was forked!\n", pid );
    }
    return 0;
}

이제 알 수 있습니다.

Osiris-2 JL: ./xx
Hello, my pid is 37589
I was forked! :D 37590
37590 was forked!
Osiris-2 JL: ./xx | cat
Hello, my pid is 37594
I was forked! :D 37596
Hello, my pid is 37594
37596 was forked!
Osiris-2 JL:

출력이 단말기에 도달하면 회선 버퍼링되기 때문에, 「Hello」라인이 앞에 표시됩니다.fork()딱 한 부만 있었어요출력의 파이핑 대상인 경우cat, 이것은 완전 버퍼링 되어 있기 때문에, 그 전에 아무것도 표시되지 않습니다.fork()두 프로세스 모두 버퍼 내에 플러시되는 'Hello' 행이 있습니다.

왜 그런지는 그 이유 없이\n포맷 문자열 끝에 값이 즉시 화면에 인쇄되지 않습니다.대신 프로세스 내에서 버퍼링됩니다.즉, 포크 조작이 끝날 때까지 실제로는 인쇄되지 않기 때문에 두 번 인쇄됩니다.

추가\n단, 버퍼를 강제로 플래시하여 화면에 출력합니다.이것은 포크 전에 발생하므로 한 번만 인쇄됩니다.

하다를 .fflush(: ★★★★★★★★★★★★★★★★★★)

printf( "Hello, my pid is %d", getpid() );
fflush(stdout);

fork()효과적으로 프로세스의 복사본을 만듭니다.를 호출하기fork() 데이터를 있습니다부모와 자녀 모두 버퍼링된 데이터는 동일합니다.다음 번에 각각 버퍼 플러시(단말기 출력의 경우 줄바꿈 인쇄 등)를 하면 그 프로세스에 의해 생성되는 새로운 출력과 더불어 버퍼링된 출력이 표시됩니다. 부모 및 stdio를 해야 합니다.fflush이치노

아이는 '', '아기', '아기', '아기', '아기', '아기', '아기', '아기', '아기', '아기', '아기', '아기', '아기', '아기', '아기', '아기', '아기',exec*자처리 하기 위해 으로 자처리 이미지(버퍼 포함)를 대체할 필요는 .fflush처리 .그러나 버퍼링된 데이터가 있는 경우 exec 실패 처리 방법에 주의해야 합니다. 함수stdio 함수)를 .write를 호출합니다._exit (오류)_Exit를 호출하는 것이 )를 호출합니다.exit또는 (버퍼링된 출력이 모두 플러시됩니다.)또는 포킹하기 전에 플러싱하여 이 문제를 방지하십시오.

언급URL : https://stackoverflow.com/questions/2530663/printf-anomaly-after-fork

반응형