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

【系统编程】进程创建

文章目录

  • 一、进程身份与相关函数
    • 进程ID相关函数
    • 用户身份相关函数
    • 用户组身份相关函数
    • 实际身份与有效身份
  • 二、`fork`函数
  • 三、创建子进程
  • 四、循环创建 n 个子进程

一、进程身份与相关函数

进程ID相关函数

  1. getpid()

    • 获取当前进程的进程 ID(PID)
    • 原型:pid_t getpid(void);
    • 返回值: 当前进程的 PID
  2. getppid()

    • 获取当前进程的父进程 ID(PPID)
    • 原型:pid_t getppid(void);
    • 返回值: 父进程的 PID

用户身份相关函数

  1. getuid()

    • 获取当前进程的实际用户 ID(UID)
    • 原型:uid_t getuid(void);
  2. geteuid()

    • 获取当前进程的有效用户 ID(EUID)
    • 原型:uid_t geteuid(void);

用户组身份相关函数

  1. getgid()

    • 获取当前进程的实际组 ID(GID)
    • 原型:gid_t getgid(void);
  2. getegid()

    • 获取当前进程的有效组 ID(EGID)
    • 原型:gid_t getegid(void);

实际身份与有效身份

类型含义说明
实际用户ID (UID) / 组ID (GID)表示进程真正归属的用户/组,通常由登录身份决定
有效用户ID (EUID) / 组ID (EGID)表示进程当前执行权限的用户/组,决定访问控制权限

二、fork函数

#include <sys/types.h>
#include <unistd.h>pid_t fork(void);
  • 成功:
    • fork之后会产生一个子进程,父子进程各自对fork函数进行返回
    • 父进程:返回子进程的 id
    • 子进程:返回 0
  • 失败:
    • 不产生子进程
  • 失败的两个主要原因是:
    1)当前的进程数已经达到了系统规定的上限,这时 errno 的值被设置为 EAGAIN。
    2)系统内存不足,这时 errno 的值被设置为 ENOMEM。

三、创建子进程

#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>// 自定义的错误打印函数
void sys_err(const char *str) {perror(str);exit(1);  // 退出程序
}int main(int argc, char *argv[])
{printf("==================before fork====================\n");pid_t pid = fork();if (pid == -1) {sys_err("fork error");}if (pid == 0) {// 子进程printf("This is a child process: %d, parent pid: %d\n", getpid(), getppid());} else if (pid > 0) {// 父进程printf("This is a parent process: %d, child pid: %d, my parent pid: %d\n", getpid(), pid, getppid());sleep(1);}printf("==================after fork====================\n");return 0;
}

在这里插入图片描述

查看所有进程信息:

ps aux

查看 fork 函数的父进程的信息:

ps aux | grep 3516

结果可见,/bin/bash是 fork 的父进程,也就是当前终端的 Shell

四、循环创建 n 个子进程

要求:

  • 使用循环创建 N 个子进程;
  • 每个子进程根据自身编号打印信息并休眠 i 秒;
  • 用 sleep + printf 区分每个子进程的执行顺序;
  • 学会控制 fork 的传播路径,避免进程爆炸。

在循环中调用 fork(),目的是想创建 N 个子进程

for (int i = 0; i < N; i++) {fork();
}
  • 实际上,会创建 2ⁿ 个进程(包括父进程),共 2ⁿ - 1 个子进程
  • 原因:每个已有的进程都执行 fork(),导致进程数量呈指数增长。
    • fork() 是复制当前进程;
    • 每个进程进入循环时,都会继续 fork;
    • 所以第 1 次 fork 产生 1 个子进程;
    • 第 2 次 fork,2 个进程继续 fork → 变 4 个;
    • 第 3 次 fork,4 个继续 fork → 变 8 个……

即:总进程数为 2ⁿ(n 为循环次数)

正确写法:

  • 只有 主父进程 执行所有 fork()
  • 每个子进程创建后立即退出循环(或整个进程);
  • 可用 sleep(i) 控制输出顺序;
  • 子进程数量就为 N,符合预期。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>int main(int argc, char *argv[]) {if (argc != 2) {fprintf(stderr, "用法: %s <子进程数量>\n", argv[0]);exit(1);}int n = atoi(argv[1]);  // 获取子进程数量for (int i = 0; i < n; i++) {pid_t pid = fork();if (pid < 0) {perror("fork 出错");exit(1);} else if (pid == 0) {// 子进程执行内容sleep(i);  // 休眠 i 秒printf("我是第 %d 个子进程,pid = %d,ppid = %d\n", i + 1, getpid(), getppid());exit(0);   // 子进程退出}// 父进程继续创建下一个子进程}// 父进程等待子进程结束(可选)sleep(n);  // 保证所有子进程输出完成printf("This is parent: %d\n", getpid());return 0;
}

在这里插入图片描述

http://www.dtcms.com/a/323464.html

相关文章:

  • 本地进行语音文字互转
  • 国内外大模型体验与评测
  • Vue2 字段值映射通用方法
  • Python 属性描述符(描述符用法建议)
  • 基于Prometheus、Grafana、Loki与Tempo的统一监控平台故障排查与解决方案
  • redis开启局域网访问
  • C++讲解---通过转换函数和运算符函数直接调用类的对象
  • Horse3D引擎研发笔记(三):使用QtOpenGL的Shader编程绘制彩色三角形
  • Aurora设计注意问题
  • 【递归、搜索和回溯】FloodFill 算法介绍及相关例题
  • 11. 为什么要用static关键字
  • 香橙派 RK3588 部署千问大模型 Qwen2-VL-2B 多轮交互式对话
  • 【工具】Python多环境管理
  • ubuntu安装ollama流程
  • Day 8: 深度学习综合实战与进阶技术 - 从优化到部署的完整流程
  • Java+Vue打造的采购招投标一体化管理系统,涵盖招标、投标、开标、评标全流程,功能完备,附完整可二次开发的源码
  • 数据结构day06
  • 102-基于Spark的招聘数据预测分析推荐系统
  • 物质和暗物质形成机制
  • 【排序算法】④堆排序
  • 工具箱许愿墙项目发布
  • AI_RAG
  • 复现论文关于3-RPRU并联机器人运动学建模与参数优化设计
  • 机器翻译实战:使用Gensim训练中英文词向量模型及可视化
  • Android之gradle和gradlew命令编译项目总结
  • 消息队列核心功能和消息队列做异步的优势
  • C++:继承[下篇]
  • Vue 使用element plus组件库提示doesn‘t work properly without JavaScript enabled
  • [ MySQL 数据库 ] 多表关联查询
  • STM32HAL库 -- 10.DMA外设实战(UART串口+DMA读取传感器数据)