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 버퍼를 비웁니다.
요청에 따른 줄별 분석(괄호 등 제거 - 마크업 편집기에 의해 선행 공백 제거):
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 );
분석 내용:
- 표준 출력을 위해 버퍼에 "Hello, my pid is 1234"를 복사합니다.말미에 새로운 회선이 없고 출력이 라인 버퍼 모드(또는 풀 버퍼 모드)로 실행되고 있기 때문에 단말기에는 아무것도 표시되지 않습니다.
- stdout 버퍼에서 정확히 동일한 재료를 사용하는 두 가지 공정을 제공합니다.
- 아이는 가지고 있다
pid == 0
행 4와 5를 실행합니다.부모의 값은 0이 아닙니다.pid
(두 프로세스 간의 몇 가지 차이 중 하나 - 값 반환:getpid()
그리고.getppid()
2개 더 있음) - 새 행을 추가하고 "I were forked!D"를 자식의 출력 버퍼에 연결합니다.출력의 첫 번째 행이 단말기에 표시되며, 출력은 라인 버퍼가 되므로 나머지 행은 버퍼에 저장됩니다.
- 모든 것이 3초 동안 멈춘다.그 후 아이는 메인 끝의 리턴을 통해 정상적으로 퇴장합니다.이 시점에서, stdout 버퍼내의 잔존 데이터가 플래시 됩니다.줄 바꿈이 없으므로 출력 위치는 줄 바꿈 끝에 남습니다.
- 부모가 여기로 와요.
- 부모는 아이가 죽을 때까지 기다린다.
- 부모가 새로운 행을 추가하고 "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
'programing' 카테고리의 다른 글
Vue를 사용하여 현재 디렉토리 내의 파일 읽기 (0) | 2022.08.27 |
---|---|
Vuex 저장소 개체의 속성에 액세스할 수 없습니다. (0) | 2022.08.27 |
C#의 #region에 해당하는 Java (0) | 2022.08.27 |
Java에서 기존 파일에 텍스트를 추가하는 방법 (0) | 2022.08.27 |
JsonNode를 POJO로 변환 (0) | 2022.08.27 |