2017-02-21 1 views
-1

저는 초보자이며 fork() 및 wait() 함수를 사용하는 방법을 배우려고합니다.포킹/대기 프로그램. 내 결과는 무엇입니까? 출력이 맞습니까?

누군가 내 코드를 실행하고 내 결과물을 말해 줄 수 있습니까?

지금 내가 점점 오전 : B C B C 에게 D E를

그러나 광산의 친구는 그것이 있어야 말한다 : B C A D E A B C

그리고 다른 하나는 그것이 있어야 말한다 : B C C D E 때문에 대기의

() 함수, 내가 자식 프로세스는 부모 전에 마쳐야했습니다 생각했다. 그래서 나는 결과물이 'E'로 끝나기를 기대한다.

그러면 가능한 출력은 어떻게됩니까? 나는 그것을 실행할 때 나는 ABCABCADE를 이해하지 못한다. 'A'는 초기 자식 프로세스에 한 번만 인쇄하면 안됩니까?

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

int main(void) { 
int pid; 

    pid= fork(); 
    if (pid == 0) { 
     fprintf(stdout, "A\n"); 
     pid= fork(); 
     if (pid==0) { 
      fprintf(stdout, "B\n"); 
      pid=fork(); 
      fprintf(stdout, "C\n"); 
     } 
     else { 
      wait(NULL); 
      fprintf(stdout, "D\n"); 
     } 
    } 
    else { 
     fprintf(stdout, "E\n"); 
     wait(NULL); 
    } 
    // your code goes here 
    return(0); 
} 
+0

'코드가 여기에 표시됩니다'라는 곳에 무엇을 작성 했습니까? 출력은 어쨌든 확실하지 않습니다. 당신은 다른 실행에 대해 다른 결과를 얻을 수 있습니다. 또한 출력을 파이프하거나 출력을 파일로 재 지정하면 다른 결과를 다시 얻을 수 있습니다. –

답변

0

부모 나 아이가 어쨌든 첫번째 때 당신에게 fork() 실행 여부를 지정하지 않은 시간을 처리하는 실행 또는 얼마나 다른 하나는 실제로 두 개의 서로 다른 코어에서 동시에 실행 여부를 점거, 또는 전에 도착 . 만약 부모가 그 자식에 대해 wait()을 성공적으로 수행했다면, wait()이 반환 되 자마자 그 자식이 종료되었음을 확신 할 수 있습니다. 그러나 다른 동기화 수단이 없으면 어린이가 수행 한 작업과 관련하여 을 통해 부모의 행동 순서를 예측하고 그 자녀를 수집하는 것은 불가능합니다.

fork() 호출의 반환 값과 관련된 조건도 살펴보십시오. 성공한 fork()은 자식 (유일한)에서 0을 반환하므로 프로그램의 동작 대부분이 정확히 하나의 프로세스에 각각 연결됩니다.

그러나 또 다른 요소가 있습니다. 동일한 열린 파일 설명에서 여러 핸들의 상호 작용입니다. fork() 일 때 두 개의 stdout 스트림 (이전에 동일한 열린 파일 설명을 참조하는 스트림)으로 끝났습니다. POSIX는 프로그램이 그 상황을 처리해야하는 방법에 대해 some restrictions을 배치합니다. 프로그램의 표준 출력이 터미널에 연결될 때 기본값 인 라인 버퍼 인 경우 프로그램 동작은 인쇄 할 각 문자열 끝에있는 줄 바꿈으로 인해 잘 정의됩니다. 그러나 stdout이 파이프에 연결된 경우와 같이 완충되어 버퍼링 된 경우 동작을 정의하기 전에 fflush(stdout)을 수행해야합니다. 따라서 포크를 실행하기 전에 fflush()에게 가장 안전합니다. 프로그램 환경이 실행 환경에 관계없이 정의되도록합니다.

이러한 고려 사항을 고려하여 프로그램을 분석하고 정의 된 동작을 제공하는 방식으로 프로그램이 실행된다고 가정하면 여러 가지 가능한 출력이 있음을 알 수 있지만 제안 사항은 그 중 하나가 아닙니다.프로그램이 동작을 정의되지 않은 방식으로 실행하면 출력에 대해 아무 것도 말할 수 없습니다. 당신이 E 인쇄 후 때까지하지 wait()했기 때문에 E는 지난 나타나도록 이유가 없다

+0

그런 다음 몇 가지 가능한 출력이 있습니까? 나는 그것을 실행할 때 나는 ABCABCADE를 이해하지 못한다. 'A'는 초기 자식 프로세스에 한 번만 인쇄하면 안됩니까? – SuperHippo

+0

@SuperHippo, 이것은 좋은 지적입니다. 현재 내 대답에 대한 업데이트가 필요합니다. 결론은 프로그램이 un * specified * behavior가 아니라 undefined * behavior를 나타냄을 의미합니다. –

+0

@SuperHippo 업데이트. –

1

.

줄 바꿈 출력을 반드시 사용해야하는 것은 아니며 포크하기 전에 보류중인 출력이 있으면 부모와 자식이 모두 버퍼링 된 텍스트를 출력합니다.

각 앞에 fflush(stdout);을 추가하십시오. fork() 그렇게하면 여러 개의 A 출력을 없애고 나머지는 이유를 설명 할 수 있습니다.

parent 
| 
| 
+------\ 
|  | 
"E" "A" 
|  | 
wait +------\ 
.  |  | 
.  wait "B" 
.  .  | 
.  .  +------\ 
.  .  |  | 
.  .  "C" "C" 
.  .  | 
.  |<----exit 
.  "D" 
.  | 
|<----exit 
| 

당신은 E이 어느 시점에 인쇄 할 수 있다고 볼 수 있지만 D 후 적어도 하나의 C 때까지 인쇄되지 않습니다 (왼쪽 일) : 다음 시간 라인입니다.

당신이

fprintf(stdout, "E\n"); 
    wait(NULL); 

의 순서를 바꾼 경우에 당신은 E 항상 어떤을 거기로하지만, 다른 C (차례로 적어도 하나의 C 이후) D 여전히 지난 수 없었다 뒤에 오는 것을 보장 할 수 그 프로세스의 종료와의 관계를 순서 짓는다.

0

출력이 완전히 확정되지 않았기 때문에 다른 실행에서 다른 결과가 나타날 수 있습니다. 또한 출력을 파이프하거나 파일로 리디렉션하면 그렇지 않은 경우와 다른 결과를 얻습니다. 자세한 내용은 printf() anomaly after fork()을 참조하십시오. 여기

도 출력 (대신 비표준 <wait.h> 헤더의 POSIX 표준 <sys/wait.h> 헤더를 사용을 강제 플러시 수있는 코드의 개정이다. 때 나를 위해 가장 자주

#include <stdio.h> 
#include <unistd.h> 
#include <sys/wait.h> 

static int flush = 0; 

static void print(const char *str) 
{ 
    printf("%s\n", str); 
    if (flush) 
     fflush(stdout); 
} 

int main(int argc, char **argv) 
{ 
    if (argc > 1) 
     flush = (argv[argc] == 0); 
    int pid = fork(); 
    if (pid == 0) 
    { 
     print("A"); 
     pid = fork(); 
     if (pid == 0) 
     { 
      print("B"); 
      pid = fork(); 
      print("C"); 
     } 
     else 
     { 
      wait(NULL); 
      print("D"); 
     } 
    } 
    else 
    { 
     print("E"); 
     wait(NULL); 
    } 
    return(0); 
} 

, cat에 파이프 때

E 
A 
B 
C 
C 
D 

, 출력은 다양하지만 주제로 변화된다 : 무료 (단, 리디렉션, 아니 명령 줄 인수를) 실행되지는 E이 먼저 나타납니다

A 
B 
C 
A 
D 
A 
B 
C 
E 

및 인수와 함께 실행 발생하도록 플러시를 강제로

A 
B 
C 
A 
B 
C 
A 
D 
E 

,이 지속적으로 얻을 :

E 
A 
B 
C 
D 
C 

스케줄러는 다른의 프로세스를 실행할 수있는 서열; 내 컴퓨터의 스케줄러가 다른 순서로 프로세스를 실행합니다. 부모 프로세스는 대개 wait()에 도달 할 때까지 실행되지만 자식은 즉시 예약되지 않으므로 출력이 자식보다 먼저 나타날 수 있습니다.

YMMV.

Mac (MacOS Sierra 10.12.3, GCC 6.3.0)에서 테스트되었습니다.