프로세스 코드 분석하는데 질문드립니다.

conan1447의 이미지

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
 
int main(void)
{
    pid_t pid;
    int i;
    for (i=0;i<3;i++){
        pid=fork();
        if (pid==-1){
            printf("Fork Error.\n");
        } else if (pid==0) {
            printf("I am child");
        }
    }
 
    if (pid!=0){
        while ((pid=waitpid(-1, NULL, 0))>0)
            if(errno==ECHILD)
                break;
            printf("I am parent and all children have exited.\n");
    }
    exit(0);
    return 0;
}

위의 코드를 실행해보면 I am child가 7개, I am parent and all children have exited가 4개 출력되고,

실행할 때마다 각각의 문장이 출력되는 순서가 다른데

이유가 무엇인가요? (자세히 설명해주시면 감사하겠습니다.)

좀비 프로세스나 고아 프로세스랑 관련 있나요?

또 I am child가 3개, I am parent and all children have exited가 1개 나오게 하려면

코드를 1줄만 추가해서 어떻게 수정하면 되나요? (2줄 이상은 안된다고 문제집에 나와서요)

익명 사용자의 이미지

1. 첫 번째 루프의 실행을 마쳤을 때 fork는 총 몇 번 실행되었을까요?

2. 그 시점에서 프로세스는 총 몇 개일까요? (힌트: 프로세스 트리를 그려 보세요)

3. 그 시점에서 pid에 남아있는 값은 무엇의 반환값일까요?

답을 듣는 건 간단하지만 직접 고민하고 생각하는 건 간단하지 않습니다.
바로 그렇기 때문에 해 볼 가치가 있죠.

그러고 싶지 않다면...

return printf("I am childI am childI am childI am parent and all children have exited.\n"), 0;

이 한 줄을 int i; 바로 다음 줄에 추가하면 됩니다. 딱 한 줄이에요. 됐죠?

익명 사용자의 이미지

만일을 대비해서 질문 원본을 기록으로 남겨둡니다.

http://archive.is/Gb2Uk

conan1447의 이미지

다시 말해서 fork 함수가 여러번 호출되서 그런 것 같은데, 정확한 원리가 무엇인가요?
왜 printf가 4번, 7번 실행되나요?

익명 사용자의 이미지

첫 번째 fork가 실행된 직후에 부모 프로세스는 어떤 상태일까요?

그리고 자식 프로세스는 어떤 상태일까요?

conan1447의 이미지

하지만 다이어그램이 의미하는 바를 제대로 설명하지는 못하겠습니다ㅠ

댓글 첨부 파일: 
첨부파일 크기
Image icon x7JPT.png41.49 KB
익명 사용자의 이미지

제가 이해를 못해서 설명해 달라는 게 아니에요.

본인이 이해하지 못하는 남의 설명, 남의 그림 옮겨다 놓기만 하면 무슨 소용입니까?

기초부터 돌아가서 이해해 보라는 뜻입니다.

fork의 역할이 뭐죠? fork를 호출한 직후에는 어떤 일이 일어나고 있을까요?

conan1447의 이미지

새로운 프로세스를 만드는(복사하는) 함수입니다.
프로세스가 생성되는데,
위 코드의 경우 for문 안에 fork가 있다보니,
처음(i=0)에는 프로세스1 하나만 있습니다.
프로세스1이 for문 안으로 들어와 fork()를 실행하면 프로세스2가 만들어지고,
이제 프로세스1은 I am child를 출력합니다.
프로세스1과 프로세스2가 for문을 두 번째로 돌 때(i=1일 때) fork()를 실행해
각각 프로세스3과 프로세스 4를 만들고, 각각 한번씩 I am child를 출력합니다.
이런식으로 해서 i=2일 때는 4번 I am child를 출력하여
총 7번(1+2+4) 출력되는 것으로 보입니다.

하지만 I am parent가 4번 출력되는 이유는 모르겠네요;;

익명 사용자의 이미지

Quote:
프로세스1이 for문 안으로 들어와 fork()를 실행하면 프로세스2가 만들어지고,
이제 프로세스1은 I am child를 출력합니다.

프로세스1? 확실해요?

conan1447의 이미지

처음의 프로세스1이 들어오고 fork()가 호출되면 프로세스2가 생성되고,
이것이 자식 프로세스(pid==0)가 되므로 printf가 실행됩니다.

라스코니의 이미지

fork()를 for 같은 loop에서 여러번 호출했을 때,
첫번째 자식 프로세스가 fork()를 실행하면 자신은 그 자식 프로세스의 부모가 되는거죠.

raymundo의 이미지

음...

물고기를 주지 말고 낚시하는 법을 가르치라는 말이 틀린 말은 아니지만 그래도 너무 엄격하신 거 아닌가 싶은 느낌이네요.

그리고 질문하신 분은, 이미 이유가 완벽하게 설명된 다이어그램이 있는데 어느 부분에서 막히시는 건지 잘 모르겠습니다만,

(올리셨던 다이어그램에 제가 프로세스 번호 P1~P8을 추가로 붙였습니다)

위 댓글 중간에 말씀하신 대로, "I am child"가 7번 출력되는 이유는 fork()가 7번 수행되기 때문입니다.

"I am parent"가 4번 출력되는 이유를 모르겠다고 하셨는데, 이왕이면 질문하신 분 생각에는 몇 번 출력되어야 할 것 같았는지 적어주셨으면 더 좋았을 것 같네요.(1번? 아니면 7번?) 아무튼 4번 출력된 이유는 fork를 실행했던 프로세스가 4개이기 때문이죠.

예를 들어 P4의 경우, P2 가 i=1일 때 fork해서 나온 자식프로세스인데, 생성된 직후 pid값은 0이었고 그래서 "I am child"를 출력했지만, 다시 루프를 돌아 i=2가 되었을 때 fork한 다음에는 pid에는 자식 프로세스 P8의 process id가 담기게 되죠. 따라서 루프가 끝난 후 아래 if(pid!=0)에 걸려서 waitpid를 하게 되고 자식(P8)이 종료된 후 "I am parent"를 출력합니다.

이런 식으로 "I am parent"은 P4, P3, P2, P1 네 개의 프로세스가 출력하게 되죠. 순서는 여러 가지가 될 수 있겠지만 언제나 P4가 P2보다는 먼저 출력할 거고, P1이 제일 마지막에 출력하겠군요.

지금 봤듯이 자식이 7개 생겨나는 이유는 이전 루프에서 자식으로 생성된 프로세스가 다음 루프에서는 자기도 fork를 하여 부모가 되기 때문이고, 따라서 본문의 마지막 질문인 "또 I am child가 3개, I am parent and all children have exited가 1개 나오게 하려면"의 답은, 자식 프로세스는 자기 할 일이 끝나면 다음 루프로 돌아가지 않고 종료되게 하는 겁니다.

// ...
        } else if (pid==0) {
            // 이왕이면 눈으로 알아보기 쉽게 출력
            printf("I am child. my pid = %d, my parent = %d, created when i = %d\n", getpid(), getppid(), i);
            // break 또는 return 또는 exit
            return;
        }
    }
 
// ..
        printf("I am parent, my pid = %d, and all children have exited.\n", getpid());

I am child. my pid = 10827, my parent = 10826, created when i = 0
I am child. my pid = 10828, my parent = 10826, created when i = 1
I am child. my pid = 10829, my parent = 10826, created when i = 2
I am parent, my pid = 10826, and all children have exited.
댓글 첨부 파일: 
첨부파일 크기
Image icon fork.png52.83 KB

좋은 하루 되세요!

익명 사용자의 이미지

문제를 다 풀어줘서 문자 그대로 긁어가기만 하면 되는 답을 올려놓는 건 상대에게 스스로 생각할 기회를 뺏는 일이지요.

개인적으로 그런 형태의 답변은 본인의 지식/능력을 과시하는 것 이상의 의의를 못 느낍니다만, 뭐 관점은 사람마다 다른 것이니까요.

세벌의 이미지

음. 이런 답변은 열심히 답변한 분 의욕을 떨어뜨리는 거 같은데요?

conan1447의 이미지

처음 댓글 주신 분은 제가 생각하기에는 너무 약올리는 것 같아서 하루종일 고민중이었는데,
친절하게 그림까지 수정해주셔서 감사드립니다.

pid가 0이 아니게 될 때 출력이 되는 것이니, 자식 프로세스를 생성할 때이니까,
P1, P2, P3, P4가 여기에 해당되는 것은 알겠습니다.

하지만 I am parent가 출력되는 순서는 아직 이해가 안가서요.

특히 왜 마지막에 P1이 I am parent를 출력하게 되나요?

Stephen Kyoungwon Kim@Google의 이미지

그 정도면 친절한 답변입니다. 미국의 질답 사이트의 de facto standard는 stackoverflow인데 거기 가서 질문을 어떻게 하는지 한 번 보세요. 전 사실 한국 개발자 사이트들의 질문자들이 흔히 갖는 이 "억울한" 정서를 이해하기 너무 힘듭니다.

근본 문제는, 의도야 어땠든, 기본 개념을 이해 못하고 특정 문제에 대한 해답을 찾기 때문에 "입에 밥을 밥숟갈로 떠서 먹여 달라"는 모양새가 되는 거예요. 그러면 답변하는 쪽에선 "대체 당신이 뭔데 내가 일하면 시급 나올 시간을 빼서 답을 달아줘야 하느냐?"고 생각하게 되지 않겠습니까? 사실 본문의 질문은 의도는 전혀 그렇지 않았다고 믿지만, 결과적으로는 상당히 무례한 질문이에요.

차라리 개념을 잘 모르겠으면 이해하려고 노력해 보고, 노력해 본 결과를 갖고 개념에 대한 질문을 올리시는 게 낫습니다.

그리고.. 질문 하는 법을 배우는 게 컴퓨터 공학을 배우는 것과 멀지 않습니다. 답변자를 편하게 한다는 건, 질문을 나이브하게 하면 답변자가 했어야 할 일을 질문자가 일부 직접할 수 있다는 거고요.

예컨대 stackoverflow는 재현 가능한, 동작하는 코드를 올리도록 요구합니다. 초보자는 큰 코드를 그냥 돌려보고 안 되면, "이게 안 된다"고 하죠. narrow down은 핵심적인 기술이고, 그게 되어야 재현가능한, 미니멀한 코드를 만들 능력이 됩니다. 그러니까 이 능력이 안 되면 여기 와서 질문하지 말고 다른 길을 강구하라는 얘기에요. 그럴 때는 차라리 디버깅을 어떻게 하는지 물어보는 게 낫습니다.

저도 꽤 오래 학생이었던 적이 있고, 때때로 어쩌다 보니 내일 모레 과제 제출 마감인데 느긋하게 책 읽을 시간은 안 되는 상황이 생겼습니다. 지나고 보니 그런 상황은 만들면 안 되었더군요. 마음이 급해서 이런 질문을 하시는 거면, 마음이 급해질 상황을 만들지 마세요.

conan1447의 이미지

케바케입니다

Stephen Kyoungwon Kim@Google의 이미지

케바케의 범위는 넘어섰어요. 간혹 친절한 분이 계셔서 설명을 해주실 수는 있습니다만, 이런 질문을 받고 화가 났다고 그 화난 분더러 뭐라 할 거리는 전혀 아니에요.

Stephen Kyoungwon Kim@Google의 이미지

전산과라면 2학년에 보통 배우고 전자과라면 3 ~ 4학년에 배우는 걸로 알고 있습니다.

그 정도라면 본인이 스스로 그 정도는 책 읽고 찾아서 아셔야 해요.

https://www.amazon.com/Computer-Systems-Programmers-Perspective-3rd/dp/013409266X

위의 책이 명저고 한국은 서울대가 교재로 써서 인터내셔널 판이 한국에도 나와 있습니다. 아직도 쓴다면 301동 구내 서점에서는 팔 테고, 교보 등 큰 서점이나 yes24 온라인 서점에서 판매할 거라고 생각합니다. 그리고 구글 검색하면 pdf로도 2판은 올라와 있어요.

아래는 fork를 설명하는, 한글로 된 사이트인데 첫 구글 검색으로 찾았습니다:
https://codingdog.tistory.com/entry/%EB%A6%AC%EB%88%85%EC%8A%A4-fork-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4%EB%A5%BC-%EC%83%9D%EC%84%B1%ED%95%9C%EB%8B%A4

먼저 이런 내용을 스스로 찾아서 읽어보시고 여전히 모르겠거든 그때 하는 게 질문입니다.

conan1447의 이미지

말씀하신 대로 개념을 제대로 이해하는게 중요하고, 잘 안된다면 어떤 식으로 이해하려고 했는지 접근 방법을 쓰는 것에 동의합니다.
그리고 답변자들이 답글을 다는데 시간을 투자하는 것에 감사하게 생각합니다.
하지만, stackoverflow에도 윗분처럼 상세하게 설명해주시는 분들도 많습니다.
그리고 참고서도 많이 보기도 하고 구글링도 많이 해보았지만, 도저히 이해가 안되어 절박한 심정으로 글을 올린 것이라서
너무 엄격한 답은 불쾌하기도 합니다. 그럴거라면 차라리 답글을 안다는게 오히려 더 나을 수도 있다고 생각합니다.

Stephen Kyoungwon Kim@Google의 이미지

질문을 스택 오버플로우에 올려보세요. 관리자가 삭제 안 하면 다행입니다. 케이스 바이 케이스라고 했는데, 저는 이 질문을 꼭 집어서도 같은 말을 할 수 있습니다.

본문의 글만 보고 첫 댓글 단 분이 답을 달았죠. 그리고는 다른 분으로 보이는 익명 사용자분이 질문을 던져가며 생각을 유도해서, 나중에 본인이 직접 다이어그램도 옮기고 parent가 네 번만 출력되는 부분은 이해할 수 없다고 했습니다.

최소한 거기까지는 스스로 이해하려고 노력하고, 이해가 된 상태에서 그 내용을 함께 적어 질문을 올려야 무성의해 보이지 않습니다. 제가 보기엔 너무 엄격하게 답 한 사람 아무도 없어요.

본문처럼 올릴 거면 안 올리는 게 나았을 질문입니다. 이게 억울하고 답답하다면 그건 질문자분 문제라고 봅니다.

라스코니의 이미지

먼저 오해 없으시기 바랍니다. 생각해 보면 백두산에 떨어진 물이 어떤 것은 서해로 흐르고 어떤 것은 동해로 흐르는 것처럼 프로그래밍 능력을 향상시키는 것도 마찬가지로 생각되네요. 단순한 문제에 대해서 short cut으로 가느냐 아니면 자체로 해결하느냐에 따라서 큰 차이가 난다고 봅니다.

누군가 질문을 했을 때 자세히 해석까지 곁들여 답변을 달아주는 분이 있다면 그 분이 정말 은인일까요? 아님 향후 질문자가 스스로 해결할 때 얻는 만족감을 얻는 기회를 빼았고 향후 뛰어난 프로그램 설계자 및 프로그래머로 성장할 동력마저도 빼앗는 원수일까요?

저는 conan1447님의 질문을 봤을 때 이런 생각이 들었습니다. 복잡한 fork() 실행이 이해가 가지 않는다면 1, 2개로 시작하면 좋을텐데. 그리고 gdb로 step-by-step으로 디버그를 해보면서 ps -ef 로 생성되는 프로세스 정보를 그때 그때마다 확인해 보면 좋을텐데.

요새 kldp에 과제 관련한 듯한 질문이 많이 올라오고 있네요. 님의 질문이 그렇다는 뜻은 아닙니다. 과제 관련한 질문은 대개 어떻게 하면 되요? 저는 아무것도 몰라서요. 이런 류의 질문이 대부분이죠. 어제는 결국 평균을 어떻게 구하면 되냐는 질문도 올라와 있군요.

차라리 과제 관련한 글만 올리는 게시판이 만들어 졌으면 좋겠습니다. 교수/교사도 학생이 인터넷에 과제 해결 요청글을 올리고 답변 받은 것을 그대로 과제 결과물로 제출하는 것을 원하는 것이 아니겠죠. 문제 해결 그 자체보다는 그 해결 과정을 통해서 문제 해결 접근 방법, 코드 구조 설계, 디버그와 같은 경험을 얻게 하는 것이 목적아닐까요? 이러한 간단한 문제도 고민없이 누군가 지어놓은 밥을 먹는 것으로 만족한다면 어떻게 향후 소프트웨어 과정을 따라갈 수 있을까요?

raymundo의 이미지

>> 특히 왜 마지막에 P1이 I am parent를 출력하게 되나요?

waitpid 를 반복 호출하는 while 루프가 있어서, 모든 자식 프로세스가 종료될 때까지는 while 루프를 벗어날 수 없기 때문이죠.

P1 이 I am parent 를 출력하려면 P2, P3, P5 가 종료된 후에나 가능합니다. 그런데 P2 가 종료되려면 마찬가지 이유로 P4 가 먼저 종료되어야만 하고...(이하 생략)

그리고 코드 들여쓰기가 잘못되어서 현혹되는 면이 있네요. I am parent 출력하는 print 문은 while 문 '바깥'에, while 과 동일한 들여쓰기 위치에 있습니다.

-----

질문 내용과 별개로 스레드가 좀 타올랐는데, 그럴 맘은 없었지만 원인 제공한 게 저라서ㅠ_ㅠ 책임이 있지 싶어서 첨언합니다.

제가 처음 "너무 엄격하신 느낌이 있다"고 말한 게 익명 답글자분을 공격하려는 의도는 없었고요(그리 받아들이신 것 같아 죄송하네요, 아무래도 글은 뉘앙스 전달이 힘들다보니). 앞서 적었듯이 저도 그런 식으로 낚시를 가르쳐주는 답을 더 좋아합니다. 그래서 만일 제가 이 글에 첫 댓글을 적는다면 앞서 적어드린 답글에 있는, getpid, getppid 를 출력하는 printf 문만 달랑 적어드렸을 겁니다. 그거 출력을 보며 다시 고민해보시라고.

근데 이미 그런 역할을 다른 분이 하고 계시길래 그냥 지켜보다가 24시간 이상 지났을 때 '이만하면 질문자도 충분히 고민 더 했겠지' 싶어서 이쯤되면 좀 더 힌트 풀어주실 때가 되었지 싶어서 가볍게 한 말이었습니다.

그리고 사족인데 저는 아는 걸 과시할만큼 잘난 사람이 아니라서요, 잘 정리한 답변을 구성하는 과정에서 제가 다시 공부하는 면도 있고 제가 잘못 알고 있었다면 바로잡을 기회도 된다는 마음입니다. 그 과정에서 적정 수준의 답변이 어느 정도인지는 정말 관점의 차이이지 싶습니다. 다들 릴렉스하시죠.

좋은 하루 되세요!

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.