Linux系统编程进程控制 -- fork()

Linux系统编程进程控制 – fork()

  • pid_t fork(void);//pid_t为int类型,进行了重载
  • pid_t getpid();// 获取当前进程的pid值
  • pid_t getppid(); //获取当前进程的父进程pid值

fork()函数用于创建一个进程,所创建的进程复制父进程的代码段/数据段/BSS段/堆/栈等所有用户空间信息;在内核中操作系统重新为其申请了一个PCB,并使用父进程的PCB进行初始化

fork函数

1.1 在linux中调用fork()函数子进程返回的父进程pid为1是什么原因

在Linux中调用fork()函数后,子进程会复制父进程的地址空间和所有资源,包括文件描述符和进程ID等信息。子进程的进程ID(PID)是通过操作系统内核自动生成的,由于进程ID是全局唯一的标识符,因此操作系统不能简单地将父进程的进程ID赋给子进程。

在调用fork()函数后,父进程和子进程是两个完全独立的进程,它们有各自的进程ID。通常情况下,子进程的进程ID会比父进程的进程ID大1。但是,如果父进程在子进程之前退出了,子进程的父进程ID会被设置为1,这是因为操作系统将所有孤儿进程(即没有父进程的进程)的父进程ID设置为1。因此,如果您在调用fork()函数后立即退出父进程,子进程的父进程ID就会被设置为1。

#include <stdlib.h> // 包含标准库头文件
#include <stdio.h> // 包含输入输出头文件
#include <unistd.h> // 包含Unix标准头文件
#include <sys/wait.h>
int main(int argc, char *argv[]) { // 主函数
    printf("before fork()\n"); // 输出字符串
    pid_t pid = fork(); // 创建子进程
    if(pid == -1) { // 如果创建子进程失败
        perror("fork() error"); // 输出错误信息
        exit(1); // 退出程序
    } else if(pid == 0) { // 如果是子进程
        printf("I am child process, my id = %d, my parent process id = %d\n", getpid(), getppid()); // 输出子进程的ID和父进程的ID
    } else if(pid > 0) { // 如果是父进程
        wait(NULL); // 等待子进程结束(注释此条语句后发生错误)
        printf("I am parent process, my child id = %d, my id is %d, my parent process id = %d\n", pid, getpid(), getppid()); // 输出父进程的ID、子进程的ID和父进程的ID
    }
    printf("============end of file.\n"); // 输出字符串
    return 0; // 返回0,表示程序正常结束
}

注释掉 wait(NULL); // 等待子进程结束后,其输出为:

 I am parent process, my child id = 90569, my id is 90568, my parent process id = 86676
============end of file.
I am child process, my id = 90569, my parent process id = 1
============end of file.

在子进程中返回的父进程为id = 1,不符合预期id = 90568

要避免该问题,可以在调用fork()函数后,在父进程中等待子进程执行完毕后再退出,这样就能确保子进程的父进程ID不会被设置为1。

可以使用wait()waitpid()函数等待子进程的结束。这些函数将挂起父进程,直到子进程退出。此时,父进程再调用exit()函数退出,确保子进程的父进程ID是正确的。

输出:

before fork()
I am child process, my id = 90132, my parent process id = 90131
============end of file.
I am parent process, my child id = 90132, my id is 90131, my parent process id = 86676
============end of file.
1.2 循环创建n个子进程

image-20230413204136811

从上图我们可以很清晰的看到,当 n 为 3 时候,循环创建了(2^n)-1 个子进程,而不是 N 个子进程。需要在循环的过程,保证子进程不再执行 fork ,因此当(fork() == 0)时,子进程应该立即 break;才正确。

#include <stdlib.h> // 包含标准库头文件
#include <stdio.h> // 包含输入输出头文件
#include <unistd.h> // 包含Unix标准头文件
#include <sys/wait.h>

int main(int argc, char *argv[]) { // 主函数
    printf("before fork()\n"); // 输出字符串

    for(int i = 0; i < 5; i++) {
        pid_t pid = fork(); // 创建子进程
        if(pid == -1) { // 如果创建子进程失败
            perror("fork() error"); // 输出错误信息
            exit(1); // 退出程序
        } else if(pid == 0) { // 如果是子进程
            printf("I am child number %d process, my id = %d, parent process id = %d\n", i+1, getpid(), getppid()); // 输出子进程的ID和父进程的ID
            break;
        } else if(pid > 0) { // 如果是父进程
            wait(NULL); // 等待子进程结束
        }
    }
    printf("============end of file.\n"); // 输出字符串
    return 0; // 返回0,表示程序正常结束
}

输出:

before fork()
I am child number 1 process, my id = 90049, parent process id = 90048
============end of file.
I am child number 2 process, my id = 90050, parent process id = 90048
============end of file.
I am child number 3 process, my id = 90051, parent process id = 90048
============end of file.
I am child number 4 process, my id = 90052, parent process id = 90048
============end of file.
I am child number 5 process, my id = 90053, parent process id = 90048
============end of file.
============end of file.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
进程编程是一种应用在Unix/Linux系统中的编程方法,其中一个重要的概念就是fork(分叉)。 在Linux中,fork是一个系统调用,它创建一个新的进程。通过fork进程可以生成一个与自己完全相同的子进程进程子进程之间的唯一区别在于它们的进程ID不同,其他方面都是一模一样的。 fork的作用是允许一个进程创建一个与自己共享资源的进程,但是拥有独立的执行空间。这样可以避免不同进程之间相互影响和干扰。 在使用fork的过程中,操作系统会将进程的所有信息(包括代码、数据、打开的文件描述符等)拷贝一份给子进程。然后,进程子进程会从fork调用的返回值中得到不同的结果。在进程中,返回的是子进程进程ID;在子进程中,返回的是0。这样,进程就可以根据fork的返回值来判断自己是进程还是子进程,从而进行不同的操作。 在实际的编程中,可以通过fork来实现各种不同的功能。比如,可以通过fork创建一个子进程来进行并发执行,提高程序的运行效率。另外,可以通过fork创建一个子进程来执行一段代码,然后通过进程来等待子进程的结束并处理子进程的结果。 总之,进程编程中的fork是一个非常重要且常用的概念,它提供了创建和管理进程的能力,为程序的并发执行和资源的管理提供了可能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值