我对fork()如何从父进程复制内存感到困惑。我试着通过写一个例子找到它:
int global_var = 0;
int main(int argc, char* argv[]){
int local_var = 1;
pid_t child;
child = fork();
if (child < 0){
cout << "Fork error: " << strerror(errno) << endl;
return 1;
}
if (child != 0 ){ // parent
cout << "Parent: global address: " << &global_var << endl;
cout << "Parent: local address: " << &local_var << endl;
++global_var;
++local_var;
cout << "Parent: global: " << global_var << endl;
cout << "Parent: local: " << local_var << endl;
}else{
cout << "Child: global address: " << &global_var << endl;
cout << "Child: local address: " << &local_var << endl;
sleep(1);
cout << "Child: global: " << global_var << endl;
cout << "Child: local: " << local_var << endl;
}
return 0;
}
我看到了结果:
父级:全局地址:0x6021a0 父级:本地地址:0x7fff942dd99c 父:全球:1 家长:本地:2 子:全局地址:0x6021a0 子:本地地址:0x7fff942dd99c 孩子:全球:0 孩子:当地人:1
为什么孩子没有看到变量的变化,即使孩子的变量与父母的变量在同一地址。请有人帮我解释一下。
提前致谢。
答案 0 :(得分:1)
孩子和父母不共享记忆。 地址具有相同的值,但它们位于不同的堆栈中,例如两个不同城市的“123 Main Street”;它们指的是记忆中的两个不同位置。孩子看不到父母做出的改变,因为这些改变没有发生在孩子的堆栈中。
答案 1 :(得分:0)
当你分叉一个进程时,它就变成了自己的程序,即父进程的副本。
在您的示例代码中,您只需在父进程中增加global_var和local_var。
试试这个看。
int global_var = 0;
int main(int argc, char* argv[]){
int local_var = 1;
pid_t child;
child = fork();
if (child < 0){
cout << "Fork error: " << strerror(errno) << endl;
return 1;
}
if (getpid() != 0 ){ // parent
cout << "Parent: global address: " << &global_var << endl;
cout << "Parent: local address: " << &local_var << endl;
++global_var;
++local_var;
cout << "Parent: global: " << global_var << endl;
cout << "Parent: local: " << local_var << endl;
}else if(getpid() == 0){ // child
cout << "Child: global address: " << &global_var << endl;
cout << "Child: local address: " << &local_var << endl;
++global_var;
++local_var;
cout << "Child: global: " << global_var << endl;
cout << "Child: local: " << local_var << endl;
}
return 0;
}
希望这会有所帮助,叉子有时会让人感到困惑。
答案 2 :(得分:0)
进程有两种类型的虚拟内存:内核和用户。 fork()时,创建一个具有单独虚拟内存的克隆子进程,该进程几乎与父进程相同。 fork()调用在父级中进行,但返回两次,一次在父级中,一次在子级中。案例由返回码区分:
int x = fork();
if(x == 0)
{
// we are in the child
}
else
{
// we are in the parent
}
除了此返回码之外,用户存储器将是相同的。内核内存有一些区别:定时器在孩子中休息,pid和ppid不同等。 通常调用execve()来跟进子进程,这将覆盖用户区域并允许子进程执行与父进程完全不同的代码。 execve()被调用一次并且永远不会返回,因为代码是过时的,例如
int x = fork();
if(x == 0)
{
// we are in the child
execve("myprog", argv, envp); // overwrites the code with that from myprog
// never get here because execve never returns
}
else
{
// we are in the parent
}