Linux fork操作之后发生了什么?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux fork操作之后发生了什么?相关的知识,希望对你有一定的参考价值。

  今天我在阅读《Unix网络编程》时候遇到一个问题:accept返回时的connfd,是父子进程之间共享的?我当时很不理解,难道打开的文件描述符不是应该在父子进程间相互独立的吗?为什么是共享的呢?fork之后父子进程之间共享了什么?堆上的变量是否也共享了呢?

  做了如下的代码测试,在fork之前先创建一个文件,在子进程中写入字符串“shenlei”,父进程读取文件内容,发现是“shenlei”。说明打开的文件描述符在父子进程之间是共享的。

  看来在《Unix网络编程》中说的是对的,当close一个文件描述符时候会将文件描述符的引用计数-1。在普通文件io操作时,只有当引用计数为0才能真正关闭该文件描述符;在socket操作时,也只有当引用计数为0时才会发送FIN,四次挥手关闭相应的socket。

 

#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
#include <iostream>

using namespace std;
static int global_val = 0;
int main()
{
	int *p = (int*)malloc(sizeof(int));
	*p=0;	
	int m = 2;
	pid_t pid ;
	int fd = open("mytest", O_RDWR | O_CREAT, 0666);
	if ((pid = fork()) < 0)
	{
		cout << "fork error" << endl;
	}
	else {
		if (pid == 0)
	{
		char buf[20]="\0";
		int res = read(fd,buf,20);
		cout<<"pid is "<<getpid()<<" res is "<<res<<" fd is "<<fd<<" buf is "<< buf<<endl;
		close(fd);
		//sleep(1);
		char bufs[8]="shenlei";
		lseek(fd, 0, SEEK_SET);		
		write(fd,bufs,strlen(bufs));
		global_val++;
		m++;
		(*p)++;
	}
		else{
		sleep(1);
		char buf[20]="\0";
		lseek(fd, 0, SEEK_SET);
		int res = read(fd,buf,20);
		cout<<"pid is "<<getpid()<<" res is "<<res<<" fd is "<<fd<<" buf is "<< buf<<endl;
		cout << *p << " " << m << " " << global_val<< endl;	
		}
	}
	return 0;
}

  然后又测试了下,一个进程中的堆对象能否共享,如上述代码所示,结论是不可以的。全局变量,静态变量,全局静态变量也都是不行的。说明在fork创建多进程之后堆栈信息会完全复制给子进程内存空间,父子进程相互独立。

某公司笔试题:当父进程调用fork()创建子进程之后,下列哪些变量在子进程中修改之后,父进程里也会相应地作出改动?

A.全局变量
B.局部变量
C.静态变量
D.文件指针

看懂了以上的分析就很简单了,答案是D。

以上是关于Linux fork操作之后发生了什么?的主要内容,如果未能解决你的问题,请参考以下文章

Github代码fork之后,如何与原仓库进行同步?

“fork()”之后的 printf 异常

「进程管理」fork之后子进程到底复制了父进程什么?

linux进程--进程间通信方式

结合中断上下文切换和进程上下文切换分析Linux内核的一般执行过程

为啥在 Linux 上 fork 或 exec 后 RLIMIT_STACK 丢失?