linux子进程继承了父进程的什么
linux子进程继承了父进程的什么详细介绍
在 Linux 中,子进程通过 fork() 或 vfork() 系统调用创建,会继承父进程的许多资源和属性,但也有部分内容是重新创建或不继承的。以下是子进程继承父进程的主要内容:
一、继承的资源和属性
- 文件描述符(File Descriptors)
- 父进程中已打开的文件描述符会被子进程复制(通过写时复制机制),默认情况下子进程可读写这些文件(除非设置了
O_CLOEXEC标志)。 - 子进程与父进程共享文件偏移量(如
lseek的位置)和文件状态标志(如O_APPEND)。
- 父进程中已打开的文件描述符会被子进程复制(通过写时复制机制),默认情况下子进程可读写这些文件(除非设置了
- 内存地址空间(部分继承)
- 子进程复制父进程的虚拟地址空间(代码、数据、堆、栈等),但采用 写时复制(Copy-on-Write, COW) 技术:
- 修改前,父子进程共享物理内存;
- 任一进程修改内存时,系统才为修改部分分配独立的物理内存。
- 子进程复制父进程的虚拟地址空间(代码、数据、堆、栈等),但采用 写时复制(Copy-on-Write, COW) 技术:
- 进程属性
- 用户 ID(UID)、组 ID(GID):子进程继承父进程的有效 UID/GID 和真实 UID/GID(特权进程除外)。
- 环境变量(Environment Variables):子进程获得父进程环境变量的副本(可通过
environ变量访问)。 - 信号处理方式:子进程继承父进程的信号处理配置(如默认处理、自定义信号处理函数),但异步信号的传递状态不会继承。
- 文件模式创建掩码(umask):子进程默认使用父进程的
umask。 - 当前工作目录(Current Working Directory) 和 根目录(Root Directory):通过
chdir()或chroot()修改的目录会被子进程继承。 - 终端关联(Controlling Terminal):若父进程关联终端,子进程也会关联同一终端。
- 其他资源
- 定时器(Timers):如
setitimer()创建的定时器会被子进程复制。 - 信号量、消息队列等 IPC 资源的访问权限:子进程继承父进程对 IPC 资源的访问权限(取决于 IPC 对象的权限设置)。
- 进程上下文的部分状态:如浮点运算状态、内存保护属性(通过
mprotect()设置)等。
- 定时器(Timers):如
二、不继承或重新创建的内容
- 进程 ID(PID):子进程有独立的 PID,父进程的 PID 为子进程的 PPID(父进程 ID)。
- 父进程 ID(PPID):子进程的 PPID 指向父进程(若父进程退出,子进程会被 init 进程收养,PPID 变为 1)。
- 未处理的信号:子进程不会继承父进程未处理的信号队列。
- 锁(Locks):如文件锁(
flock())或互斥锁(pthread_mutex)不会自动继承,需重新获取。 - 统计信息:如 CPU 时间、进程运行时间等,子进程从 0 开始统计。
- 某些内核资源:如
setrlimit()设置的资源限制,子进程默认继承父进程的限制,但可通过setrlimit()单独修改。
三、关键机制:写时复制(COW)
- 内存优化:fork 后,父子进程的内存空间在物理上共享,仅当任一进程修改数据时才复制对应页面,避免了直接复制大量数据的开销。
- 适用场景:适用于 fork 后立即调用
exec()执行新程序的场景(此时子进程无需修改父进程的内存,COW 几乎不产生额外开销)。
总结
子进程继承了父进程的大部分 静态配置(如 UID、环境变量、文件描述符)和 共享资源(通过 COW 机制),但拥有独立的 动态状态(如 PID、统计信息)。理解这些特性对编写多进程程序(如服务器 fork 子进程处理请求)至关重要。