【系统编程】进程创建
文章目录
- 一、进程身份与相关函数
- 进程ID相关函数
- 用户身份相关函数
- 用户组身份相关函数
- 实际身份与有效身份
- 二、`fork`函数
- 三、创建子进程
- 四、循环创建 n 个子进程
一、进程身份与相关函数
进程ID相关函数
-
getpid()
- 获取当前进程的进程 ID(PID)
- 原型:
pid_t getpid(void);
- 返回值: 当前进程的 PID
-
getppid()
- 获取当前进程的父进程 ID(PPID)
- 原型:
pid_t getppid(void);
- 返回值: 父进程的 PID
用户身份相关函数
-
getuid()
- 获取当前进程的实际用户 ID(UID)
- 原型:
uid_t getuid(void);
-
geteuid()
- 获取当前进程的有效用户 ID(EUID)
- 原型:
uid_t geteuid(void);
用户组身份相关函数
-
getgid()
- 获取当前进程的实际组 ID(GID)
- 原型:
gid_t getgid(void);
-
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;
}