В частности, как fork () обрабатывает динамически выделенную память из malloc () в Linux? - PullRequest
31 голосов
/ 04 января 2011

У меня есть программа с родительским и дочерним процессами.До fork () родительский процесс вызывал malloc () и заполнял массив некоторыми данными.После fork () эти данные нужны ребенку.Я знаю, что могу использовать канал, но следующий код работает:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main( int argc, char *argv[] ) {
    char *array;
    array = malloc( 20 );
    strcpy( array, "Hello" );
    switch( fork() ) {
    case 0:
        printf( "Child array: %s\n", array );
        strcpy( array, "Goodbye" );
        printf( "Child array: %s\n", array );
        free( array );
        break;
    case -1:
        printf( "Error with fork()\n" );
        break;
    default:
        printf( "Parent array: %s\n", array );
        sleep(1);
        printf( "Parent array: %s\n", array );
        free( array );
    }
    return 0;
}

Вывод:

Parent array: Hello
Child array: Hello
Child array: Goodbye
Parent array: Hello

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

Всегда ли это так в Linux?Если да, то где находится документация, которая это поддерживает?Я проверил справочную страницу fork (), но она не упоминала динамически выделенную память в куче.

Спасибо

Ответы [ 3 ]

35 голосов
/ 04 января 2011

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

На самом деле, этоне копируется в самом начале, он имеет значение «Копировать при записи», что означает, что один из процессов (родительский или дочерний) пытается изменить скопированную страницу, чтобы они не вредили друг другу, и при этомвсе данные из точки fork (), доступные для них.

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

Более подробная информация доступна здесь и здесь .

5 голосов
/ 04 января 2011

После разветвления ребенок полностью независим от родителя, но может наследовать определенные вещи, которые являются копиями родителя.В случае кучи у ребенка концептуально будет копия кучи родителей во время разветвления.Однако изменения в голове в адресном пространстве ребенка будут изменять только копию ребенка (например, путем копирования при записи).

Что касается документации: я заметил, что в документации обычно указывается, что все скопировано, кроме для бла-бла-бла.

2 голосов
/ 04 января 2011

Короткий ответ «грязный при записи» - более длинный ответ .. намного длиннее.

Но для всех целей и задач - рабочая модель, которую на уровне C можно с уверенностью предположить, состоит в том, что сразу после fork () два процесса абсолютно идентичны - то есть дочерний объект получает точную копию на 100% -- (но ненадолго вокруг возвращаемого значения fork ()) - и затем начинают расходиться, когда каждая сторона изменяет свою память, стек и кучи.

Таким образом, ваш вывод несколько отклонен - ​​дочерний процесс начинает с тех же данных, что и родительский, скопированных в его собственное пространство, - затем изменяет их - и видит, что он изменен, в то время как родительский процесс продолжает свою собственную копию.*

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

Dw.

...