3

我在 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() 是如何工作的,但这似乎很奇怪..

我需要解释为什么地址相同,尽管它们是单独的变量。

4

5 回答 5

12

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

于 2009-08-10T00:51:08.153 回答
8

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

于 2009-08-10T00:51:23.177 回答
4

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

于 2009-08-10T00:51:10.120 回答
0

这是否也适用于 pthread_mutex 对象。假设我在父级中有互斥锁,它在特定函数中被锁定和解锁。现在父进程创建一个子进程。父母和孩子都可以同时调用这个函数(父母直到孩子退出才真正被阻塞,因为父母是一个多线程程序,产生孩子的线程只有一个被阻塞)。那么互斥对象状态是否在两个进程之间共享?如果在父级中,互斥锁被锁定,则子级被创建 子级开始运行第一个孩子看到互斥锁处于锁定状态,因为它刚刚从父级继承了互斥锁对象,现在孩子解锁互斥锁 现在父级中这个互斥锁的状态如何- 仍然锁定(因为父母从未解锁)或解锁,因为孩子已解锁。

可以调用这样的函数来锁定/解锁父母和孩子的全局互斥锁吗?

于 2009-09-25T08:20:05.503 回答
0

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

于 2010-04-18T09:17:30.923 回答