fork()해서 힙주소를 자식에게 넘겨주는거 올바른 방법인가요?

rain의 이미지

      1
      2
      3 #include <stdio.h>
      4 #include <stdlib.h>
      5 #include <string.h>
      6 #include <unistd.h>
      7 #include <wait.h>
      8
      9 void child(char* ptr) {
     10     printf(__FUNCTION__ ": PID=%d, ptr -> [%s]\n", getpid(), ptr);
     11 }
     12
     13 int main() {
     14
     15     char* ptr;
     16
     17     ptr = (char*) malloc (1024);
     18
     19     strncpy(ptr, "Hello, My name is Jonathan", 1024);
     20
     21     switch (fork()) {
     22         case -1:
     23             break;
     24         case 0:
     25             child(ptr);
     26             printf("child terminated PID=%d...\n", getpid());
     27             exit(0);
     28             break;
     29         default:
     30             break;
     31     }
     32
     33     wait(0);
     34
     35     printf("parent terminated PID=%d...\n", getpid());
     36
     37     return 0;
     38 }

아래는 실행 결과입니다.

child: PID=7309, ptr -> [Hello, My name is Jonathan]
child terminated PID=7309...
parent terminated PID=7308...

fork()해서 자식 프로세스를 하나 생성을 하고 부모가 힙영역에 데이터를
넣어 주면 자식은 이를 가져가는 구조의 프로그램을 짜보려구 합니다.
그래서 처음엔 공유메모리를 사용해서 해봤는데요.
문득 위와 같이 힙영역의 포인터만 넘겨주어도 될꺼 같다는 생각이 들어서
해봤는데 위 실행 결과처럼 잘 나오네요.
여기에 플래그만 하나 둬서 부보와 자식이 플래그에 따라 메모리에 데이터를
읽고 쓰면 될꺼 같은데요.
이렇게 하는 방법이 괜찮은 건가요?
처음엔 두 프로세스 간에 통신을 하기 위해선 IPC의 방법밖에 없다는 생각을
했었거든요. 이런 구조의 프로그램에선 IPC를 쓸 필요가 없는 건가요?
아님 제가 멀 잘못한건지요.
조언 부탁드립니다.

eminency의 이미지

ipc는 부모자식간이 아닌 서로 동떨어진 process끼리도 데이타를 주고받는 것이 가능하므로 쓰이는 것입니다. 제가 말하는 ipc는 물론 공유메모리나 메시지 큐같은 것이구요...

질문하신 분처럼 fork를 할 경우는 자식이 부모의 프로세스를 복사해서 생기는 것이므로 결과도 당연히 위와 같이 나오겠죠.
다시 말하면 위의 코드는 메모리를 할당한 ptr을 자식에게 넘겨주는 것이 아니라 메모리 영역 자체도 복사 되어서 자식에게 넘어가는 것이므로 fork한 이후에는 부모가 ptr에 데이터를 써도 자식은 읽을 수가 없습니다. 서로 다른 메모리를 쓰고 있으니까요.

fork이후에 데이터 동기화나 교환이 필요한 것이 아니라면 fork 되기 전에 데이터를 쓰고 fork해서 작업하면 되겠지만 그런 경우를 원하시는게 아닌 것 같은데요...

노루가 사냥꾼의 손에서 벗어나는 것 같이, 새가 그물치는 자의 손에서 벗어나는 것 같이 스스로 구원하라 -잠언 6:5

rain의 이미지

아래의 코드 처럼 부모와 자식간에 데이터를 주고 받으려고 짜봤는데
역시 않되네요..아래의 코드가 올바르게 짜졌다면
fork()를 하면 부모와 자식의 힙 메모리가 각각 존재하기 때문에 통신이
않되는 거죠? 맞나요?

      1
      2
      3 #include <stdio.h>
      4 #include <stdlib.h>
      5 #include <string.h>
      6 #include <unistd.h>
      7 #include <wait.h>
      8
      9 #define BUF_SIZE 1024
     10
     11 enum FLAG {
     12     FLAG_EMPTY,
     13     FLAG_FILL,
     14 };
     15
     16 struct message {
     17     int flag;
     18     char buf[BUF_SIZE];
     19 };
     20 typedef struct message msg_t;
     21
     22 void reader(msg_t* msg) {
     23     while (1) {
     24         if (msg->flag == FLAG_FILL) {
     25             printf(__FUNCTION__ ": Read [%s]\n", msg->buf);
     26             msg->flag = FLAG_EMPTY;
     27         }
     28         printf(__FUNCTION__ ": wait write...\n");
     29         sleep(3);
     30     }
     31 }
     32
     33 void writer(msg_t* msg) {
     34     static int id = 0;
     35
     36     msg->flag = FLAG_EMPTY;
     37
     38     while (1) {
     39         if (msg->flag == FLAG_EMPTY) {
     40             snprintf(msg->buf, BUF_SIZE,
     41                     "Message %d from PID=%d", id++, getpid());
     42             msg->flag = FLAG_FILL;
     43
     44             printf(__FUNCTION__ ": %s\n", msg->buf);
     45         }
     46         printf(__FUNCTION__ ": wait read...\n");
     47
     48         sleep(3);
     49     }
     50 }
     51
     52 int main() {
     53
     54     msg_t* msg;
     55
     56     msg = (msg_t*) malloc (sizeof(msg_t));
     57
     58     msg->flag = FLAG_EMPTY;
     59
     60     if (msg == NULL) {
     61         printf("malloc failed\n");
     62         exit(0);
     63     }
     64
     65     switch (fork()) {
     66         case -1:
     67             break;
     68         case 0:
     69             reader(msg);
     70             printf("child terminated PID=%d...\n", getpid());
     71             exit(0);
     72             break;
     73         default:
     74             writer(msg);
     75             break;
     76     }
     77
     78     wait(0);
     79
     80     printf("parent terminated PID=%d...\n", getpid());
     81
     82     return 0;
     83 }

실행 결과 입니다.

$ ./a.out
reader: wait write...
writer: Message 0 from PID=9169
writer: wait read...
reader: wait write...
writer: wait read...
reader: wait write...
writer: wait read...
reader: wait write...
writer: wait read...

세상에서 가장 이해하기 힘든 것은 내 자신이 그것을 이해할 수 있다는 것이다.
- 알베르트 아인슈타인 -

rain의 이미지

공유메모리를 사용할 때는 동적 크기의 자료 구조(연결리스트. 트리..등등)를 공유할 수는 없나요?
연결리스트를 쓴다면 노드가 생길 때만다 힙에 메모리를 잡아야 하잖아요.
그러한 경우는 어떻게 해야 하나요..?

세상에서 가장 이해하기 힘든 것은 내 자신이 그것을 이해할 수 있다는 것이다.
- 알베르트 아인슈타인 -

bejoy4him의 이미지

생각하고 계신 이유가 맞는듯 합니다....

fork()가 되면 버추얼 메모리가 따로 하나더 자식 프로세스에게 할당되기 때문일것 같은데...

fork()문 이전의 코드는 정확히 같으나 그 이후의 코드는 다른 별개의(물론 부모자식 간이지만...) 메모리(버추얼메모리)를 가지는 두 프로세스가 떠 있다고 봐야 하는거 아닐까요?

따라서 malloc해서 받는 주소값이 부모 자식이 같긴 하지만.... 그거야 각자 버추얼 메모리 내에서의 주소값을 말하는거고... 실질적으로 물리적 메모리는 다른 곳을 가르키고 있음으로 공유할수 없다... 뭐 이런거 아닐까요???

흠.. 요즘엔 뭐든지 자신이 없어지는군요... 내가 말하고 있는게 정말 맞는지.. ^^;;; 에구 에구

bejoy4him의 이미지

아 그리고 공유메모리(shared memory) 사용시에 그것을 동적으로 할당할수 없을까? 하는 질문인가요?

좀 어렵지 않을까요?

일단 공유메모리라는것이 일정 메모리영역을 확보해놓고 그곳에 데이터를 썼다가 지웠다가 하는것이 일반적인데... 동적 할당이라고 한다면....
이미 존재하는 영역에서 늘어나야 할 영역을 더한 메모리 영역을 시스템으로부터 다시 할당받고 그곳에 복사하고 추가된 부분은 기록하고, 이전에 할당받았었던 영역은 제거하고...

어찌보면 메모리 동적할당하고 똑같은것으로 보이기도 하지만, IPC리소스를 그렇게 빈번하게 할당 해제하는것은 시스템에 큰 부하를 줄것으로 보이구요...

뭐 그런 비슷한 이유로, 공유메모리의 키값을 링크드 리스트의 노드안에 집어 넣어서(노드에 포인터 가지고 앞뒤 노드를 표현하는 대신 키값을 가지고 공유메모리에 접속할수 있도록 할수 있지 않을까요?) 만들면 만들순 있겠지만.....

성능은 영 보장이 되지 않을것 같다는 생각이 드네요.....

흠... 저의 괘변이 아니길..... ㅡㅡ;;

advanced의 이미지

bejoy4him wrote:

따라서 malloc해서 받는 주소값이 부모 자식이 같긴 하지만.... 그거야 각자 버추얼 메모리 내에서의 주소값을 말하는거고... 실질적으로 물리적 메모리는 다른 곳을 가르키고 있음으로 공유할수 없다... 뭐 이런거 아닐까요???

흠.. 요즘엔 뭐든지 자신이 없어지는군요... 내가 말하고 있는게 정말 맞는지.. ^^;;; 에구 에구

맞습니다

주소는 같더라도 가상주소 이기 때문에 실제는 다른 곳입니다

fork 를 통해 복사 했을당시에는 같은 내용이지만

그래서 그 이후에 변경 되는 내용은 완전히 별개가 됩니다

rain의 이미지

벌써 해가 뜨네요...^^
새벽에...그리고 아침인데도 답변을 친절하게 해주셔서...
많은 공부가 됐습니다....

한가지 더 궁금한게 있습니다.

아래와 같은 시스템 콜을 커널에 추가하고

int sys_hello(void* ptr) {
      char hello[] = "hello";
      copy_to_user(ptr, hello, sizeof(hello));
}

어플리케이션에서 아래와 같이 시스템 콜로 부터 데이터를 받아 오는 거에서요.

sys_hello(shread_memory_ptr);

제가 해보니까 되더군요.
물론 공유메모리를 통해 다른 프로세스가 커널이 공유메모리에 쓴 데이터를
접근하구요.
전체적인 구조는 이런 식이거든요

커널 모듈 -> [공유메모리] 
           +     +
           +     +-> 프로세스 1
           +
           +-> 프로세스 2
이런 식으로 구성하는게 잘못된건 아닌지 궁금합니다.

세상에서 가장 이해하기 힘든 것은 내 자신이 그것을 이해할 수 있다는 것이다.
- 알베르트 아인슈타인 -

bacrika의 이미지

공유메모리 사용을 이런 식으로 풀면 안됩니다.
단순히 같은 메모리를 사용 할 수 있다면, "정보를 주고 받아 일을 처리한다"

상당히 위험한 발상입니다. 세마포어나 쉐어드 메모리는 처음에 보면 복잡하고 이해하기 힘든 방식을 사용 하는것 같지만 이게 정석입니다.
최소한의 필요한 장치를 두고 그 장치를 이용하는것이지요.

별 필요 없다고 생각마시고, 있으니까 써본다고 생각하고 자주 써봐야 합니다.
쓰다보면 왜 필요한지도 알게되고 꼭 필요한 부분임을 깨닿게 되죠... 보통은 책에서 왜 필요한지도 설명해 줍니다. 이런걸 무시하고 코딩하면 나중에 밤샘합니다.

rain의 이미지

bacrika wrote:

공유메모리 사용을 이런 식으로 풀면 안됩니다.
단순히 같은 메모리를 사용 할 수 있다면, "정보를 주고 받아 일을 처리한다"

상당히 위험한 발상입니다.

죄송합니다만 위험한 발상이라 하심은 커널에서 공유메모리에 데이터를 쓰는
것을 말씀하시는 건가요?
정확히 어떤 방식을 말씀하시는지 집어 주심 더 많은 도움이 될거 같습니다.
^^

세상에서 가장 이해하기 힘든 것은 내 자신이 그것을 이해할 수 있다는 것이다.
- 알베르트 아인슈타인 -

bacrika의 이미지

공유 메모리에 정보를 공유하게 되더라도 읽고 쓰는 순서가 정확해야 된다른 의미 입니다.

한놈은 쓰기만 하고, 한놈은 읽기만 하더래도
쓴후에 알려주어 한번만 읽게 해줘야 한다라는 이야기죠.

테스트 프로그램 할때부터 cpu 헛일 안 시키게 해야 나중에 밤샘 안한다는 이야기 였습니다.

cdpark의 이미지

단순히 한 쪽에서 쓰고, 반대쪽에서 읽더라도 lock을 해 줘야 안전합니다.

한 쪽에서 ""Hello, World" 자리에 "Welcome!"의 절반만 썼을 때에 반대쪽에서 읽어간다면 "Wello, World"라는 문장을 읽어갈 수도 있습니다.

쓰기/읽기 연산이 atomic하다는 보장이 없는 한에는요.

rain의 이미지

동기화는 당연히 해야겠죠....^^a
좋은 충고 감사드립니다...

그럼....커널에서 공유메모리 쪽으로 데이터를 쓰는 것은
괜찮나요...물론 시스템 콜을 호출하는 프로세스가 공유메모리에
대한 동기화를 처리하고요...

시스템 콜을 등록해서 해봤을 땐 됐는데...비정상적인 방법은 아닌지..해서요..

세상에서 가장 이해하기 힘든 것은 내 자신이 그것을 이해할 수 있다는 것이다.
- 알베르트 아인슈타인 -

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.