当前位置: 首页 > article >正文

什么是unix中的fork函数?

一、前言

在本专栏之前的文档中已经介绍过unix进程环境相关的概念了,本文将开始介绍unix中一个进程如何创建出新进程,主要是通过fork函数来实现此功能。本文将包含如下内容:
1.fork函数简介
2.父进程与子进程的特征
3.如何使用fork创建新进程。

二、fork函数简介

一个进程调用fork函数会创建一个新的进程。fork函数的函数原型如下:

#include <unistd.h>
pid_t fork(void);
fork函数被调用一次,但是返回两次(子进程返回0,父进程返回子进程的PID)如果出错,返回-1

新创建的进程称为子进程。在调用fork函数后,父进程和子进程继续执行fork后续的程序。可以通过fork的返回值来区别子进程和父进程需要执行的操作。
调用fork后,会将父进程拷贝一份,包含进程的存储空间(数据空间、堆、栈)。
ps:需要注意的是,父进程和子进程只共享正文段,其他部分都是在内存中重新拷贝一份的。

2.1 写时复制

上面提到在调用fork后会拷贝父进程除了正文段以外的存储空间,这种设计其实是比较浪费内存的,父进程的很多数据子进程其实是用不到的。
因此,很多unix-like系统采用写时复制的技术,将父进程的存储空间和子进程共享,这部分空间被设置为只读,当父进程或子进程试图修改这部分的内容时,才会为需要修改的部分在内存中制作一个副本。

2.2 父进程和子进程的执行顺序

在调用fork后,父进程和子进程的执行顺序是不确定的,这取决于内核的调度算法。如果要实现父进程和子进程的同步,需要使用同步机制。

2.3 文件共享

fork后,父进程的所有打开的子进程的文件描述符都会被复制到子进程中。比如父进程重定向了标准输出,子进程的标准输出也会重定向。

除了打开的文件以外,子进程还会共享父进程的如下内容:

1.用户ID、组ID、进程组ID、会话ID
2.控制终端
3.当前工作目录、根目录
4.文件模式创建屏蔽字
5.信号屏蔽和安排
6.资源限制
7.存储映像 …

三、参考代码

使用fork函数的参考代码如下:

/*************************************************************************
        > File Name: fork_test.c
        > Author: conbiao
        > Created Time: 2024年09月23日 星期一 10时34分25秒
 ************************************************************************/

/***********************************************************************
 *                             HEADER
 **********************************************************************/
#include <stdio.h>
#include <unistd.h>

/***********************************************************************
 *                              MACRO
 **********************************************************************/


/***********************************************************************
 *                          GLOBAL VARIABLE
 **********************************************************************/


/***********************************************************************
 *                       FUNCTION DESCRIPTION
 **********************************************************************/



/***********************************************************************
* FUNCTION NAME:
 ***********************************************************************
*
* Summary:
*
* Params:
*
* Return:
*
***********************************************************************/


/***********************************************************************
 *                                MAIN
 **********************************************************************/
int main(int argc, char *argv[])
{
    int ret = 0;
    int num = 10;
    pid_t pid;

    printf("%s: start!\n",__func__);


    if((pid = fork()) < 0)
    {
        printf("%s: fork fail!\n",__func__);
    }
    else if(pid == 0)
    {
        printf("%s: This is child process!\n",__func__);
        num += 10;
    }
    else
    {
        usleep(500000);
        printf("%s: This is parent procee,child's pid is: %d\n",__func__,pid);
    }

    printf("%s: num = %d\n",__func__,num);

    return ret;
}

运行结果如下:
在这里插入图片描述

(3-1)
如上代码的运行结果其实也说明了一个问题,子进程的进程空间中,单独存在一个num变量,所以在子进程中对num变量进行修改,最终改变的只是子进程进程空间中的num,父进程的num还是原来的。

参考资料:

《UNIX环境高级编程(第3版) (史蒂文斯 (W.Richard Stevens) 拉戈 (Stephen A.Rago)) (Z-Library)》


http://www.kler.cn/a/316444.html

相关文章:

  • EKF 自动匹配维度 MATLAB代码
  • 简单讲解关于微信小程序调整 miniprogram 后, tabbar 找不到图片的原因之一
  • Docker部署GitLab服务器
  • 家政预约小程序数据库设计
  • JOGL 从入门到精通:开启 Java 3D 图形编程之旅
  • whisper.cpp: PC端测试 -- 电脑端部署音频大模型
  • 【RabbitMQ】快速上手
  • Spring Boot 2.x基础教程:实现文件上传
  • [Unity Demo]从零开始制作空洞骑士Hollow Knight第五集:再制作更多的敌人
  • 【艾思科蓝】前端框架巅峰对决:React、Vue与Angular的全面解析与实战指南
  • 经典sql题(七)查找直播间最大在线人数
  • HDL coder使用手册
  • 【产品思考】低代码理解与国内落地
  • 【python】数据爬虫,抓取并分析豆瓣电影信息
  • 1网络安全的基本概念
  • 【Nginx】Nginx 监控详解
  • git学习【完结】
  • 【安当产品应用案例100集】017-助力软件服务商高效集成多因素认证
  • python -- assert函数
  • stm32单片机个人学习笔记7(TIM定时中断)
  • 虚幻引擎解决构建问题
  • 通往AGI的皇冠:逻辑推理能力
  • [创业之路-151] :职能部门/非经营部门 VS 业务部门/经营部门划分与职责
  • 某准网爬虫逆向
  • 掌握Spring Boot数据库集成:用JPA和Hibernate构建高效数据交互与版本控制
  • TypeScript学习笔记2