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。

时间: 2025-01-21 05:23:09

Linux fork操作之后发生了什么?的相关文章

linux内核分析之进程fork操作

最近线上遇见了奇怪的现象,redis在做rdb持久化的时候,后台曝出can not allocat memory的错误 具体错误参见redis模块中的错误分析 这里主要说明一下fork(),以及copy-on-write操作 linux内核在2.6以后对fork操作加入copy-on-write,提高系统的可靠性和高性能 首先说明的是fork(),只是一次资源的确认(这里由vm.overcommit参数决定), 网上很多对overcommit参数的说均misunderstanding 简单来讲,

Linux fork那些隐藏的开销

fork是一个拥有50年历史的陈年系统调用,它是一个传奇!时至今日,它依旧灿烂. 一个程序员可以永远不用read/write,也可以不懂mmap,但必须懂fork.这是一种格调! fork没有参数,它是如此简单,是UNIX哲学的布道者或者说卫道者们的首选,它被写进了几乎每一本操作系统教科书里,成了 创建新进程的绝佳范式 ,fork站在原地,似乎在闭着眼睛蔑视 Windows的CreateProcess ,它的参数是如此之多,如此之复杂,在UNIX的世界,简单就是一切! 然而UNIX却不是整个世界

linux文件操作

1.linux文件操作 cat test.txt | head -n 100 查看开始100行 cat finalout.txt | head -n 100 | cut -d , -f 2   安装,分割各行,取第2个位置的数据 cat test.txt |sed 's/""//g' 查看下效果 cat finalout.txt | head -n 10 | cut -d , -f 2 按,切割 cat part_name_tmp.txt | cut -d \" -f 2 &

关于Linux文件操作1.1

本文章记录本人在学习Linux中遇到的一些比较好的题目,给大家分享一下. 先来实验题目: 编程实现一个程序,功能是每一秒钟向屏幕打印当前系统时间,和当前行号示例如下 该程序应该无限循环,直到强制中断该进程为止(比如按Ctrl-C中断程序).接着再启动程序,将系统时间追加到原文件之后,并且序号能够接续上次的序号: 好了看完题目后我们应该想的是,实现这么一个功能我们需要什么知识? 我们实现功能的逻辑是什么? 我们在写代码中有什么细节需要注意的(PS:使代码尽善尽美!) a):  先花五分钟想一下这个

linux下操作gpio寄存器的方法

一. 在驱动中: 1. 用的时候映射端口:ioremap; #define GPIO_OFT(x) ((x) - 0x56000000) #define GPFCON (*(volatile unsigned long *)(gpio_va + GPIO_OFT(0x56000050))) gpio_va = ioremap(0x56000000, 0x100000); // 物理地址0x56000000, 映射区分配的大小0x100000字节 这样映射过后,就可以直接操作寄存器了: 配置3引脚

linux内存操作--ioremap和mmap学习笔记

最近在做视频输出相关的东西,对于预留给framebuffer的内存使用不是很清楚,现在找到一些资料整理一下,以备使用. 对于一个系统来讲,会有很多的外设,那么这些外设的管理都是通过CPU完成.那么CPU在这个过程中是如何找到外设的呢? 尽管在一个系统中会有诸多的外设,在每个外设的接口电路中会有多个端口.但是如果系统能够每个端口都被赋予一个具体的地址值,那么在系统中就能轻易的找到任何一个外设.系统在管理的时候,不管是内存还是外设都需要分配一个内存地址.对于一个32bit的系统来讲,可寻址的范围为2

linux基本命令操作(一)

常用系统命令: [[email protected] ~]# uname    //查看内核信息// Linux [[email protected] ~]# uname  -r       //只显示内核版本// 2.6.18-348.el5 [[email protected] ~]# uname  -a       //显示主机名.内核.硬件平台等全部信息a--all// Linux localhost.localdomain 2.6.18-348.el5 #1 SMP Wed Nov 2

linux基本命令操作(二)

·        du命令使用: [[email protected]]# du       //后没有选项和参数,默认评估当前目录下的所有目录的大小,当然也包括当前目录的大小// 237     ./grub 12      ./lost+found 6555    . [[email protected]]# ls config-2.6.18-348.el5  initrd-2.6.18-348.el5.img  System.map-2.6.18-348.el5 file1.txt]   

linux文件目录操作的相关命令

linux文件目录操作的相关命令 mkdir rmdir tree touch stat cp mv rm mkdir 功能说明:建立空目录 语 法:mkdir [-p][--help][--v][-m <目录属性>][目录名称] 补充说明:mkdir可建立目录并同时设置目录的权限. 选项: -m<目录属性> 建立目录时同时设置目录的权限. [[email protected]_18_121_centos ~]# mkdir -m 775 qin [[email protected