fork() системный вызов и пространство памяти процесса

я цитирую "Когда процесс создает новый процесс с помощью вызова fork (), только сегменты общей памяти совместно используются между родительским процессом и недавно раздвоенным дочерним процессом. Копии стека и кучи сделаны для вновь созданного процесса "из решений" концепции операционной системы " Silberschatz.

но когда я попробовал эту программу

#include  <stdio.h>
#include  <sys/types.h>

#define   MAX_COUNT  200

void  ChildProcess(void);                /* child process prototype  */
void  ParentProcess(void);               /* parent process prototype */

void  main(void)
{
         pid_t  pid;
         char * x=(char *)malloc(10);

         pid = fork();
         if (pid == 0) 
            ChildProcess();
         else 
            ParentProcess();
        printf("the address is %pn",x);
}

void  ChildProcess(void)
{
          printf("   *** Child process  ***n");
}

void  ParentProcess(void)
{
         printf("*** Parent*****n");
}

результат такой:

*** Parent*****
the address is 0x1370010
   *** Child process  ***
the address is 0x1370010

и родитель и ребенок печатая такой же адрес который в кучи.

может кто-нибудь объяснить мне противоречие здесь. пожалуйста, четко укажите, что все вещи, разделяемые родителем и ребенком в пространстве памяти.

5 ответов


цитирую сам себя из другого потока.

  • когда выдается системный вызов fork (), копия всех страниц соответствующий родительский процесс создается, загружается в отдельный расположение памяти ОС для дочернего процесса. Но это не нужен в определенных случаях. Рассмотрим случай, когда ребенок выполняет системный вызов "exec" или выход из системы очень скоро после fork(). Когда child необходим только для выполнения команды для родительского процесса, нет необходимости копировать страницы родительского процесса, так как exec заменяет адресное пространство процесса, который его вызвал, на команда должна быть выполнена.

    в таких случаях используется метод, называемый copy-on-write (COW). С этот метод, когда происходит вилка, страницы родительского процесса не являются скопировано для дочернего процесса. Вместо этого страницы совместно используются дочерний и родительский процесс. Всякий раз, когда процесс (Родительский или дочерний) изменяет страницу, отдельную только копия этой страницы для того процесса (родительского или дочернего), который выполнил модификацию. Затем этот процесс будет использовать только что скопированную страницу, а не общий во всех будущих ссылках. Другой процесс (который не изменял общую страницу) продолжает использовать исходную копию страница (которая больше не является общей). Эта техника называется копировать-на-запись, так как страница копируется, когда какой-либо процесс записывает он.

  • большинство современных процессоров вводят уровень косвенности, называемый виртуальный адрес. С виртуальными адресами, память каждого процесса начинается в" том же " месте, например, с нуля. Каждый процесс думает, что у него есть вся машина к себе, хотя очевидно, что на самом деле это не так.

    таким образом, эти виртуальные адреса являются переводами физических адресов и не представляют собой одно и то же пространство физической памяти, чтобы оставить более практический пример, мы можем сделать тест, если мы скомпилируем и запустим несколько раз программу, которая отображает направление статической переменной, такой как эта программа.

    #include <stdio.h>
    
    int main() {
        static int a = 0;
    
        printf("%p\n", &a);
    
        getchar();
    
        return 0;
    }
    

    невозможно получить один и тот же адрес памяти в два различные программы, если мы обращайтесь непосредственно к физической памяти.

    и результаты, полученные при выполнении программы несколько раз...

enter image description here


да, оба процесса используют один и тот же адрес для этой переменной, но эти адреса используются разными процессами и, следовательно, не находятся в одном и том же виртуальное адресное пространство.

Это означает, что адреса одинаковы, но они не указывают на одну и ту же физическую память. Вы должны прочитать больше о виртуальной памяти, чтобы понять это.


вероятно, вы используете свою программу в операционной системе с виртуальной памятью. После fork() звонок, родитель и ребенок имеют отдельные адресные пространства, поэтому адрес 0x1370010 не указывает на одно и то же место. Если один процесс пишет *x, другой процесс не увидит изменения. (На самом деле это может быть одна и та же страница памяти или даже один и тот же блок в файле подкачки, пока он не будет изменен, но ОС гарантирует, что страница будет скопирована, как только родитель или ребенок пишет ему, насколько программа может судить, он имеет дело со своей собственной копией.)


адрес тот же, но адресное пространство не. Каждый процесс имеет свое собственное адресное пространство, поэтому 0x1370010 родителя не совпадает с 0x1370010 ребенка.


когда ядро fork()s процесс, скопированная информация памяти наследует ту же адресную информацию, так как куча эффективно копируется как есть. Если бы адреса были другими, как бы вы обновляли указатели внутри пользовательских структур? Ядро ничего не знает об этой информации, поэтому эти указатели будут признаны недействительными. Следовательно,физическая адрес может измениться (и на самом деле часто будет меняться даже во время жизни вашего исполняемого файла даже без fork()ing, но ... --3-->логическое адрес остался прежним.