О системном вызове fork и глобальных переменных - PullRequest
2 голосов
/ 10 августа 2009

У меня есть эта программа на C ++, которая разветвляет два новых процесса:

#include <pthread.h>
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <cstdlib>
using namespace std;

int shared;

void func(){
  extern int shared;
  for (int i=0; i<10;i++)
        shared++;
  cout<<"Process "<<getpid()<<", shared "
        <<shared<<", &shared "
        <<&shared<<endl;
}

int main(){
  extern int shared;
  pid_t p1,p2;
  int status;
  shared=0;
  if ((p1=fork())==0) {func();exit(0);};
  if ((p2=fork())==0) {func();exit(0);};
  for(int i=0;i<10;i++)
        shared++;
  waitpid(p1,&status,0);
  waitpid(p2,&status,0);;
  cout<<"shared variable is: "<<shared<<endl;
  cout<<"Process "<<getpid()<<", shared "
        <<shared<<", &shared "
        <<&shared<<endl;
}

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

Тем не менее, адрес памяти общих переменных остается тем же, вы можете попробовать скомпилировать и просмотреть выходные данные программы. Как это можно объяснить? Я не могу этого понять, я думал, что знаю, как работает fork (), но это кажется очень странным ..

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

Ответы [ 5 ]

10 голосов
/ 10 августа 2009

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

7 голосов
/ 10 августа 2009

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

4 голосов
/ 10 августа 2009

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

0 голосов
/ 18 апреля 2010

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

0 голосов
/ 25 сентября 2009

Это относится и к объектам pthread_mutex. Скажем, у меня есть мьютекс в родительском объекте, который блокируется и разблокируется в определенной функции. Теперь родитель создает дочерний процесс. И родитель, и потомок могут вызывать эту функцию одновременно (родитель не блокируется до тех пор, пока дочерний процесс не завершится, так как родитель - многопоточная программа, поток, который порождает дочерний элемент, блокируется только один). Итак, является ли состояние объекта мьютекса общим для двух процессов? Если в родителе, мьютекс был заблокирован тогда ребенок был создан ребенок бежит первым ребенок видит мьютекс в заблокированном состоянии, поскольку он только что унаследовал объект мьютекса, как и от родителя теперь ребенок разблокирует мьютекс Каково состояние этого мьютекса в родительском элементе сейчас - все еще заблокировано (потому что родитель никогда не разблокирован) или Разблокировано, потому что потомок разблокировал его.

Можно ли вызывать такую ​​функцию, которая блокирует / разблокирует глобальные мьютексы от родителя и потомка?

...