fork后父子进程共享资源

本文通过一个具体示例探讨了Unix环境中fork机制下父子进程间的变量共享问题。实验结果显示,子进程获得的是父进程变量的副本,对副本的修改不会影响到父进程。此外,还详细列出了fork后父子进程共享及不共享的资源。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

fork后父子进程共享资源

Unix环境高级编程中8.3节中说,“子进程是父进程的副本。例如,子进程获得父进程数据空间、堆和栈的副本。注意,这是子进程所拥有的副本。父进程和子进程并不共享这些存储空间部分。父进程和子进程共享正文段。”

书中还预留了例子说明子进程对变量所做的改变并不影响父进程中该变量的值。

/**
 * fork.c
 * 探讨父子进程共享变量问题
 **/

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int globvar = 6;        /* external variable in initialized data */
char buf[] = "a write to stdout\n";

int 
main(void)
{
    int var;    /* automatic variable on the stach */
    pid_t pid;

    var = 88;
    if (write(STDOUT_FILENO, buf, sizeof(buf)-1) != sizeof(buf)-1)
    {
        perror("write error");
        exit(1);
    }
    printf("before fork\n");    /* we don't flush stdout */

    if ((pid = fork()) < 0)
    {
        perror("fork error");
        exit(1);
    } else if (pid == 0) {    /* child */
        globvar++;          /* modify variables */
        var++;
    } else {
        sleep(2);           /* parent */
    }

    printf("pid = %ld, glob = %d, var = %d\n", (long)getpid(), globvar, var);
    exit(0);
}

编译和运行程序,如下:

/myblog/source/fork# gcc fork.c -o fork
/myblog/source/fork# ./fork
a write to stdout
before fork
pid = 12071, glob = 7, var = 89
pid = 12070, glob = 6, var = 88

如上,可以看出,fork后子进程只是获得了父进程的副本,所有变量的变更都只在各自进程中有效。

实际上,fork后子进程和父进程共享的资源还包括:

  • 打开的文件
  • 实际用户ID、实际组ID、有效用户ID、有效组ID
  • 添加组ID
  • 进程组ID
  • 会话期ID
  • 控制终端
  • 设置-用户-ID标志和设置-组-ID标志
  • 当前工作目录
  • 根目录
  • 文件方式创建屏蔽字
  • 信号屏蔽和排列
  • 对任一打开文件描述符的在执行时关闭标志
  • 环境
  • 连接的共享存储段(共享内存)
  • 资源限制

父子进程之间的区别是:

  • fork的返回值
  • 进程ID
  • 不同的父进程ID
  • 子进程的tms_utime,tms_stime,tms-cutime以及tms_ustime设置为0
  • 父进程设置的锁,子进程不继承
  • 子进程的未决告警被清除
  • 子进程的未决信号集设置为空集
参考文献

[1] Unix环境高级编程(第3版)

[2] http://blog.youkuaiyun.com/u012138828/article/details/39031823

<think>好的,用户想了解在C++中使用fork创建多进程后,哪些资源会被共享。我需要结合提供的引用资料来回答这个问题。 首先,根据引用[4],fork创建子进程会拷贝父进程的资源,而不是共享,所以各自修改数据不会影响对方。这说明一般情况下,资源是拷贝的,但可能存在例外。 然后,引用[2]和[3]提到fork的基本用法,子进程复制父进程的地址空间。但系统为了效率,可能使用写时复制(COW)技术,这时候资源在未修改时是共享的,直到有写入操作才会复制。不过引用里没有直接提到COW,可能需要确认是否属于隐含知识。 接下来,需要考虑哪些资源是共享的。通常来说,文件描述符在fork后会共享,因为子进程会复制父进程的文件表项,导致同一文件偏移量。引用中没有提到这点,但根据常规知识,这属于共享资源的一部分。 其他共享资源可能包括:打开的文件的文件描述符、文件指针的位置、信号处理函数等。而独立的部分包括内存变量、堆栈数据等,因为每个进程有自己的地址空间。 总结起来,需要分清楚“共享”和“复制”的区别。fork后,子进程获得父进程资源的副本,但某些资源如文件描述符可能指向相同的系统级资源,所以表现出共享的行为。但根据引用[4],资源并不共享,所以这里的共享可能是指内核中的同一资源,比如文件描述符表项,而用户空间的数据是独立的。 最后,整理出共享的资源包括文件描述符、信号处理程序,以及可能的命名管道等。需要明确说明哪些是复制但表现为共享,哪些是真正共享的。</think>在C++多进程编程中,`fork()`调用会创建一个父进程几乎完全相同的子进程。关于资源共享机制,需从以下三个层面分析: ### 一、进程资源的复制机制 通过`fork()`创建子进程会复制父进程的**完整虚拟地址空间副本**,包括: - 堆内存段(如`malloc`分配的内存) - 栈内存段(局部变量) - 数据段(全局变量、静态变量) - 代码段(程序指令) 例如父进程有全局变量`int global = 10;`,子进程修改为`global = 20;`后,父进程的`global`仍保持10[^4]。 ### 二、显式共享的资源 以下三类资源会真正实现共享: 1. **文件描述符** - 子进程继承父进程打开的文件描述符表 - 共享文件偏移量指针(如同时写入同一文件会交错输出) ```c++ int fd = open("data.txt", O_WRONLY); fork(); write(fd, "test", 4); // 父子进程都会写入同一文件位置 ``` 2. **内存映射文件** - 使用`mmap()`创建的文件映射区域 - 修改会同步到磁盘文件但不会在进程间自动同步 3. **命名资源** - 命名管道(FIFO) - System V共享内存 - 消息队列等IPC资源 ### 三、内核级共享机制 | 资源类型 | 共享特性 | 示例场景 | |-----------------|----------------------------------|--------------------------| | 信号处理函数 | 子进程继承信号处理器设置 | `signal(SIGINT, handler)`| | 用户ID/组ID | 保持相同的身份标识 | 权限校验场景 | | 进程组/会话ID | 维持进程间关系 | shell作业控制 | | 文件锁 | 锁状态被子进程继承 | `flock()`锁文件操作 | ### 四、写时复制优化(COW) 现代操作系统通过**Copy-On-Write**技术优化资源复制: 1. 父子进程初始共享物理内存页 2. 当任一进程尝试修改内存页时 3. 内核自动创建该页的独立副本 4. 该机制对进程完全透明 这种机制使得`fork()`的实际资源消耗远小于完全复制的情况[^3]。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值