linux学习(11):父子进程

文章详细介绍了进程的创建,特别是通过fork函数创建子进程的过程。在创建后,父进程和子进程在初期共享数据,遵循“读时共享,写时拷贝”的原则,即在没有写操作时,父子进程共享同一内存区域,但尝试修改时会复制内存页,形成独立的地址空间。文中还提供了测试代码以演示这一概念,并提到了GDB的使用和调试多进程程序的方法。
摘要由CSDN通过智能技术生成
  1. 进程的创建

系统允许一个进程创建新的进程,新进程即为子进程,子进程还可以创建新的子进程,形成进程的树结构模型

#include <sys/types.h>
#include <unistd.h>

pid_t fork(void);
    函数的作用:用于创建子进程。
    返回值:
        fork()的返回值会返回两次。一次是在父进程中,一次是在子进程中。
        在父进程中返回创建的子进程的ID,
        在子进程中返回0
        如何区分父进程和子进程:通过fork的返回值。
        在父进程中返回-1,表示创建子进程失败,并且设置errno

通过fork返回值在父进程和子进程之间的区别来区分两者

父子进程之间的关系:

区别:

1.fork()函数的返回值不同

父进程中: >0 返回的子进程的ID

子进程中: =0

2.pcb中的一些数据

当前的进程的id pid

当前的进程的父进程的id ppid

信号集

共同点:

某些状态下:子进程刚被创建出来,还没有执行任何的写数据的操作

- 用户区的数据

- 文件描述符表

父子进程对变量是不是共享的?

- 刚开始的时候,是一样的,共享的。如果修改了数据,不共享了。

- 读时共享(子进程被创建,两个进程没有做任何的写的操作),写时拷贝。

重点:“读时共享,写时拷贝”

写时拷贝是一种可以推迟甚至避免拷贝数据的技术。

内核此时并不复制整个进程的地址空间,而是让父子进程共享同一个地址空间。

只用在需要写入的时候才会复制地址空间,从而使各个进行拥有各自的地址空间。

也就是说,资源的复制是在需要写入的时候才会进行,在此之前,只有以只读方式共享。

在子进程中对父进程数据进行修改时,会将该数据复制一份到子进程自己的虚拟地址空间中。因此,在初始阶段,父子进程共享同一个物理内存区域,并且这个区域被标记为只读状态。

如果父或者子进程尝试修改这个共享内存区域,则操作系统会为该进程分配一个新的内存页,并将原始页内容复制到新页上。这样,就形成了两个不同的虚拟地址空间

需要注意的是,fork函数并没有完全克隆整个父进程虚拟地址空间,而只是复制了必要部分(如代码段、数据段等),以便让子进程能够执行独立于父进程之外的任务。

读时共享、写时拷贝针对的是物理内存,读时会有两个独立的虚拟内存空间,指向同一个物理内存。

测试代码

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>

int main() {

    int num = 10;

    // 创建子进程
    pid_t flag = fork();

    // 判断是父进程还是子进程
    if(flag > 0) {
        // 如果大于0,返回的是创建的子进程的进程号,当前是父进程
        printf("parent process, pid : %d, ppid : %d\n", getpid(), getppid());
        printf("parent num : %d\n", num);
        num += 10;
        printf("parent num += 10 : %d\n", num);

    } else if(flag == 0) {
        // 当前是子进程
        printf("child process, pid : %d, ppid : %d\n", getpid(),getppid());
        printf("child num : %d\n", num);
        num += 100;
        printf("child num += 100 : %d\n", num);
    }

    // for循环
    for(int i = 0; i < 3; i++) {
        printf("i : %d , pid : %d\n", i , getpid());
        sleep(1);
    }

    return 0;
}

代码解释:

上述代码中,num变量物理地址上被复制一份,父进程对他所有的num加10,子进程对他所有的num加100,并且两个进程都会执行下面的for循环

值得注意的是,子进程不会进行fork(),子进程的执行起点是fork函数之后

  1. gdb多进程调试

别忘了编译方式

//一般编译
gcc test.c -o test
//当需要使用gdb时要加上-g
gcc test.c -o test -g

gdb的快捷键

查看行: l
运行程序: r
继续运行到断点 c
在第x行设置断点  b x
查看断点 i b
查看调试模式  show follow-fork-mode
逐句编译调试 n

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值