关于fork系统调用和全局变量

时间:2009-08-10 00:47:30

标签: c++ unix linux-kernel fork

我在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 个答案:

答案 0 :(得分:10)

操作系统正在使用virtual memory和类似的技术来确保每个进程在同一地址看到不同的内存单元(虚拟或读取);只共享显式共享的内存(例如通过shm),默认情况下所有内存在不同的进程之间是分开的。

答案 1 :(得分:7)

这称为“虚拟地址”。每个进程都有自己的地址空间,每个地址都意味着不同的东西,具体取决于进程。 fork()创建一个副本,而不是共享数据(从技术上讲,它们可能会在写入时进行共享拷贝,但这与前期复制具有相同的效果)。 IOW,变量“shared”不在进程之间共享。

答案 2 :(得分:4)

现代系统上的指针与实际硬件内存地址不对应。而是地址映射到由操作系统管理的虚拟空间。因此,当它们实际上不是时,两个不同进程的指针地址可能看起来是相同的。

答案 3 :(得分:0)

这是否也适用于pthread_mutex对象。假设我在父项中有互斥锁,在某个特定函数中被锁定和解锁。现在,父级创建子进程。父级和子级都可以同时调用此函数(父级不会被阻塞直到子级退出,因为父级是多线程程序,生成子级的线程只有一个被阻止)。 互斥对象状态也是如此 - 在两个进程之间共享? 如果在父母,    互斥锁被锁定了    然后孩子被创造了    孩子先跑    child看到互斥锁处于锁定状态,因为它刚刚继承了来自父对象的互斥对象    现在孩子解锁互斥锁  现在这个互斥体的状态如何 - 仍然被锁定(因为父项从未解锁)或解锁,因为孩子已解锁它。

可以调用这样一个函数来锁定/解锁来自父节点和子节点的全局互斥锁吗?

答案 4 :(得分:0)

是的,你认为是正确的,但为了节省一些内存,内部页面在父和子之间共享,直到子进行exec系统调用或修改任何变量或数据结构。在父和子之间共享.....如果页面被子项修改,那么该页面将被复制到单独的内存区域并将被分配给子项。如果它被父项修改,那么该页面将被复制到单独的内存区域并分配给父