@dariasweetsun

Разное адресное пространство для дочернего и родительского процесса (fork, mmap)?

На самом деле тут два вопроса (но они связаны между собой).

Вопрос #1:
Никак не получается понять почему переменная которая была объявлена до вызова fork() (то есть в родительском процессе) имеет тот же адрес и в дочернем процессе. Хотя насколько мне известно дочерний процесс будет иметь своё виртуальное адресное пространство и соответственно (как я понимаю) та переменная должна иметь другой адрес, но это не так. Тем не менее, всё работает так как будто они действительно изолированы друг от друга (изменения в дочернем не видны в родительском)

Вопрос #2:
Почему при использовании munmap() в дочернем процессе (перед его завершением), в родительском процессе всё ещё можно получать доступ и изменять содержимое "маппнутой" памяти??? (Есть догадка, что это будет связано с ответом на первый вопрос).

Код программы:
#include <iostream>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/wait.h>

int main(int argc, char* argv[])
{
    void* shared = mmap(NULL, sizeof(int), PROT_READ |  PROT_WRITE, 
                        MAP_SHARED | MAP_ANONYMOUS, -1, 0);
    
    int* sharedValue = static_cast<int*>(shared);

    *sharedValue = 0;
    std::cout << "before forks sharedValue: " << sharedValue << '\n';
    std::cout << "before forks *sharedValue: " << *sharedValue << '\n';

    int value = 0;
    std::cout << "before forks &value: " << &value << '\n';
    std::cout << "before forks value: " << value << '\n';
    
    int parentpid = getpid();
    int childpid;
    for(int i = 0; i < 2; ++i)
    {
        int forkret = fork();
        switch (forkret)
        {
        case -1:
            std::cerr << "Fork failed...\n";
            exit(EXIT_FAILURE);
        
        case 0:
            childpid = getpid();
            std::cout << "Child: pid " << childpid << '\n';
            std::cout << "child &value: " << &value << '\n';
            std::cout << "child value: " << value << '\n';
            std::cout << "child sharedValue: " << sharedValue << '\n';
            std::cout << "child *sharedValue: " << *sharedValue << '\n';
            value = childpid;
            *sharedValue = childpid;
            std::cout << "child value = pid: " << value << '\n';
            std::cout << "child *sharedValue = pid: " << value << '\n';
            munmap(sharedValue, sizeof(int));
            std::cout << "child munmap() called\n";
            exit(EXIT_SUCCESS);

        default:
            std::cout << "Parent: pid " << parentpid << '\n';
            wait(0);
            std::cout << "Child terminated\n";
            std::cout << "parent &value: " << &value << '\n';
            std::cout << "parent value: " << value << '\n';
            std::cout << "parent sharedValue: " << sharedValue << '\n';
            std::cout << "parent *sharedValue: " << *sharedValue << '\n';
            value = parentpid;
            *sharedValue = parentpid;
            std::cout << "parent value = pid: " << value << '\n';
            std::cout << "parent *sharedValue = pid: " << value << '\n';
        }
    }
    std::cout << "Parent terminated\n";
    return 0;
}


Вывод в консоли:
before forks sharedValue: 0x7ffff7ffb000
before forks *sharedValue: 0
before forks &value: 0x7fffffffdc74
before forks value: 0
Parent: pid 18027
Child: pid 18034
child &value: 0x7fffffffdc74
child value: 0
child sharedValue: 0x7ffff7ffb000
child *sharedValue: 0
child value = pid: 18034
child *sharedValue = pid: 18034
child munmap() called
Child terminated
parent &value: 0x7fffffffdc74
parent value: 0
parent sharedValue: 0x7ffff7ffb000
parent *sharedValue: 18034
parent value = pid: 18027
parent *sharedValue = pid: 18027
Parent: pid 18027
Child: pid 18035
child &value: 0x7fffffffdc74
child value: 18027
child sharedValue: 0x7ffff7ffb000
child *sharedValue: 18027
child value = pid: 18035
child *sharedValue = pid: 18035
child munmap() called
Child terminated
parent &value: 0x7fffffffdc74
parent value: 18027
parent sharedValue: 0x7ffff7ffb000
parent *sharedValue: 18035
parent value = pid: 18027
parent *sharedValue = pid: 18027
Parent terminated
  • Вопрос задан
  • 231 просмотр
Решения вопроса 1
gbg
@gbg Куратор тега Linux
Любые ответы на любые вопросы
Это особая, коровья магия (CoW, Copy On Write)

fork просто метит страницы родителя как CoW и немедленно запускает потомка. Реальное копирование произойдет только если потомок будет что-то туда писать.

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

Войдите, чтобы написать ответ

Похожие вопросы