#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main( int argc, char *argv[] ){
FILE *fptr;
pid_t pid;
fptr = fopen("Shared File.txt", "a");
pid = fork();
if( pid > 0 ){ // parent process
int counter = 0;
while( counter < 10 ){
fprintf(fptr, "a");
++counter;
}
wait(NULL);
}
else{
int counter = 0;
while( counter < 5 ){
fprintf(fptr, "b");
++counter;
}
}
return 0;
}
이 코드를 실행하면 코드에 의해 생성된 파일에 다음 메시지가 포함됩니다. bbbbbaaaaaaaaaa
이 코드를 실행할 때마다 동일한 메시지가 나타납니다. 쓰기 파일을 섞인 순서로 처리하지 않는 이유는 무엇입니까?
운영 체제가 처음에 하위 프로세스를 종료하려고 하는 이유는 무엇입니까?
메시지에 대한 나의 기대는 다음과 같습니다. 프로세스 간 지속적인 전환이 없는 baabbaaabaaabaa입니다.
답변1
아버지와 아들 사이의 일정은 (적어도)자식 프로세스가 실행될 때그리고포크 시스템 호출은 어떻게 작동하나요?.
하지만 이 경우에도 일반 파일에 쓰기를 stdio
사용하고 있습니다 . fprintf()
기본적으로 stdio
시스템 호출 오버헤드를 절약할 만큼 충분한 데이터가 기록될 때까지 출력은 일반 파일로 버퍼링됩니다. x86 Linux에서는 일반적으로 4096바이트 청크로 작성하는 것처럼 보이지만 버퍼링을 수동으로 설정하지 않으면 이를 기대할 수 없습니다(참조setbuf()
그리고 친구들).
strace
프로그램에서 수행한 시스템 호출 표시와 같은 명령을 사용하여 이를 확인할 수 있습니다.
따라서 어떤 프로세스가 먼저 실행될지 예측할 수 없지만 이 경우 s가 a
연속적으로 기록되고 b
s도 기록된다는 것을 예측할 수 있습니다. 당신은 bbbbbaaaaaaaaaa
또는 중 하나만 얻을 수 있으며 aaaaaaaaaabbbbb
, 어느 것을 얻는지는 거의 운의 문제입니다.
답변2
나는 기본적으로 @ikkachu에 동의합니다.
당신이 얻을 것 bbbbbaaaaaaaaaa
또는 aaaaaaaaaabbbbb
예측할 수 있는 것. 운영 체제는 하위 프로세스가 완료될 때까지 기다린 wait(NULL)
다음 상위 프로세스가 종료됩니다. 종료 시 버퍼가 플러시되면 하위 프로세스가 먼저 쓰기를 시작합니다.
그러나 예측 가능한 버퍼에 의존하지 마십시오. 필요한 경우 명시적 새로 고침을 사용하세요.
답변3
사용자 ilkkachu는 버퍼링이 출력에 어떤 영향을 미치는지에 대해 잘 설명했습니다. 내 대답은 버퍼링을 제거하면(예: fprintf
호출을 pair 로 대체하면 어떻게 되는지 설명합니다 . 이 경우 s 와 s 가 write
엄격하게 교대로 표시됩니다 . 이는 쌍에 대한 호출로 인해 일정이 변경되기 때문입니다. 하나의 프로세스에 작성하면 프로세스가 블록된 다음 해당 차례를 전달합니다. 다른 프로세스로 이동하는 등의 작업을 수행합니다.a
b
write
write를 호출하면 어떤 일이 일어날지 상상해 봅시다.아니요막혔습니다. 그런 다음 시간 척도를 고려해야 합니다. 최신 프로세서는 초당 수십억 개의 명령을 실행할 수 있지만 예약 빈도는 일반적으로 100Hz에서 1000 사이이므로 한 번에 한두 개가 아닌 s a
및 s의 실행 시간을 얻게 됩니다. b
헤르츠. 프로세스는 선점되고 다른 프로세스가 실행되도록 예약되기 전에 최대 수천만 개의 명령을 실행할 수 있습니다. 시스템 호출 오버헤드를 고려하더라도 이는 연속된 a
s 또는 b
s의 매우 긴 문자열을 인쇄하는 데 프로세스 시간을 제공합니다.
답변4
ikkachu와 Johan은 자신이 하는 행동을 관찰하는 이유를 아주 잘 설명했기 때문에 각 프로세스가 스트림을 플러시하고 잠시 휴면 상태가 되도록 프로그램을 약간 다시 작성했습니다(각 스레드가 매번 다른 방식으로 시차를 두고 기회를 얻도록). 엇갈린 효과를 더 명확하게 확인하세요.
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main(void) {
FILE *fptr = stdout;
pid_t pid;
int counter = 0;
pid = fork();
if(pid > 0) { // parent process
while(counter++ < 10) {
fprintf(fptr, "aa");
fflush(fptr);
sleep(1);
}
wait(NULL);
puts("");
} else {
while(counter++ < 5) {
fprintf(fptr, "bbbb");
fflush(fptr);
sleep(1);
}
}
}
여러 번 실행하면 때때로 다른 결과가 나타납니다.
~ $ ./thread
aabbbbaabbbbaabbbbaabbbbaabbbbaaaaaaaaaa
~ $ ./thread
aabbbbaabbbbaabbbbaabbbbaabbbbaaaaaaaaaa
~ $ ./thread
aabbbbaabbbbaabbbbaabbbbbbbbaaaaaaaaaaaa
~ $ ./thread
aabbbbaabbbbaabbbbaabbbbaabbbbaaaaaaaaaa