多进程相关函数
一,进程号获取函数
1.getpid函数
| 所需头文件 |
#include <sys/types.h> #include <unistd.h> |
| 原型 | pid_t getpid(void) |
| 功能 | 获取当前进程自身的进程号 |
| 参数 | 无 |
| 返回值 | 返回当前进程自身的进程号 |
代码示例:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc,const char *argv[])
{
pid_t pid = fork();
if(pid == -1)
{
perror("创建子进程失败\n");
return -1;
}
else if(pid == 0)
{
printf("子进程的pid:%d\n",getpid());
}else if(pid > 0)
{
printf("父进程的pid:%d\n",getpid());
}
while(1);
return 0;
}
2.getppid函数
| 所需头文件 |
#include <sys/types.h> #include <unistd.h> |
| 原型 | pid_t getppid(void) |
| 功能 | 获取当前进程的父进程的进程号 |
| 参数 | 无 |
| 返回值 | 返回当前进程的父进程的进程号 |
代码示例:
// 获取父进程号
// 函数:getppid()
// 参数:无
// 返回值:父进程的pid
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc,const char *argv[])
{
pid_t pid = fork();
if(pid == -1)
{
perror("创建子进程失败\n");
return -1;
}
else if(pid == 0)
{
printf("我是子进程的,我的父进程号为:%d\n",getppid());
}else if(pid > 0)
{
printf("我是父进程的,我的父进程号为:%d\n",getppid());
}
return 0;
}
二,进程退出函数
1.exit函数(是一个库函数,不是一个系统调用)
| 所需头文件 | #include <stdlib.h> | |
| 原型 | void exit(int status) | |
| 功能 |
正常终止进程,且status & 0377 (按位与运算后的值)会被返回给父进程 C标准规定了两个常量 EXIT_SUCCESS和EXIT_FAILURE,它们可被传递给exit()函数 |
|
| 参数 | status | 退出状态值 |
| 返回值 | 无 | |
代码示例:
include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, const char *argv[])
{
#if 0
printf("hello");
//exit是一个库函数.不是一个系统调用
//所以在查看该函数的时候,是man 3 exit
//exit(0); //exit在正常退出之前.会做一系列的清理工作
exit(EXIT_SUCCESS); //exit(0)等价于exit(EXIT_SUCCESS)
while(1){}
#else
// 创建子进程
pid_t pid = fork();
if (pid == -1)
{
perror("创建子进程失败");
return -1;
}
else if (pid == 0)
{
// 子进程
while (1)
{
printf("hello\n");
sleep(1);
exit(EXIT_SUCCESS); //exit(0):正常退出
}
}
else if (pid > 0)
{
// 父进程
while (1)
{
printf("world\n");
sleep(1);
}
}
#endif
return 0;
}
2._exit函数(它是一个系统调用,不是库函数)
| 所需头文件 | #include <unistd.h> | |
| 原型 | void_exit(int status); | |
| 功能 |
立即终止进程,且status & 0377(按位与运算后的值)会被返回给父进程 C标准库为exit函数规定了EXIT_SUCCESS和EXIT_FAILURE常量,由于其值通常为0和1; 也可传递给_exit兼容使用,但_exit本身是系统调用,不依赖这些宏; |
|
| 参数 | status | 退出状态值 |
| 返回值 | 无 | |
代码示例:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, const char *argv[])
{
#if 0
printf("hello");
//_exit不是一个库函数.是一个系统调用
//所以在查看该函数的时候,是man 2 _exit
//_exit(0); //_exit在正常退出之前.不会做一系列的清理工作
_exit(EXIT_SUCCESS); //_exit(0)等价于_exit(EXIT_SUCCESS)
while(1){}
#else
// 创建子进程
pid_t pid = fork();
if (pid == -1)
{
perror("创建子进程失败");
return -1;
}
else if (pid == 0)
{
// 子进程
while (1)
{
printf("hello\n");
sleep(1);
_exit(EXIT_SUCCESS); //_ exit(0):正常退出
}
}
else if (pid > 0)
{
// 父进程
while (1)
{
printf("world\n");
sleep(1);
}
}
#endif
return 0;
}
三,资源回收函数
1.wait函数
| 所需头文件 |
#include <sys/types.h> #include <sys/wait.h> |
|
| 原型 | pid_t wait(int *wstatus); | |
| 功能 |
父进程阻塞,等待任意一个子进程结束;若没有子进程结束,wait会一直等待; 当有子进程终止时,它会回收该子进程的资源,并通过wstatus获取子进程的退出状态值 |
|
| 参数 | wstatus |
用于存储子进程的退出状态值的内存空间首地址 wstatus若为空(NULL),表示忽略子进程退出时的状态 wstatus若不为空,表示将子进程退出状态写入该指针指向的内存,供父进程后序用宏解析 |
| 返回值 |
成功返回终止子进程的PID 如果调用进程没有子进程或者是调用出错,返回-1,同时会设置errno来指示错误原因 |
|
代码示例:
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc,const char *argv[])
{
//fork 函数,创建子进程
pid_t pid = fork();
if(pid == -1)
{
perror("创建子进程失败\n");
return -1;
}
else if(pid == 0)
{
printf("我是子进程,我的进程id是%d\n",getpid());
exit(EXIT_SUCCESS); //子进程正常退出
//exit(1000); //子进程非正常退出,退出状态是一个非0值
}
else if(pid > 0)
{
int status = 0; //保存子进程的状态值
//pid_t wait_ret =wait(NULL);//等待子进程的结束,不关注子进程的状态
pid_t wait_ret = wait(&status);//等待子进程的结束,关注子进程的状态
printf("我是父进程,我的进程id是%d\n",getpid());
if(wait_ret == -1)
{
perror("没有子进程或者是调用失败");
return -1;
}
printf("终止的子进程的pid是%d\n",wait_ret);
//针对于status这个子进程的退出状态码
//是需要进行宏解析的,这样的话才可以得到正确的退出状态码
//printf("子进程的退出状态值是:%d\n",status);
//进行宏解析
if(WIFEXITED(status))
{
printf("子进程正常退出,退出状态是:%d\n",WEXITSTATUS(status));
}
else if(WIFSIGNALED(status))
{
printf("子进程非正常退出(子进程被信号终止),信号是:%d\n",WTERMSIG(status));
}
}
return 0;
}
2.wait函数状态解析宏
子进程正常退出:
WIFEXITED(wstatus):若子进程是正常终止(调用exit()/_exit()或从 main()返回),则返回true;
WEXITSTATUS(wstatus):仅当WIFEXITED为true时使用,返回子进程的退出状态码(即exit(n)中的n,取低8位);
子进程被信号终止:
WIFSIGNALED(wstatus):若子进程是被信号终止(如SIGKILL等),则返回true;
WTERMSIG(wstatus):仅当WIFSIGNALED为true时使用,返回导致子进程终止的信号编号(如9对应SIGKILL);
WCOREDUMP(wstatus):仅当WIFSIGNALED为true时使用,若子进程终止时产生了核心转储文件,则返回true;
子进程被信号暂停:
WIFSTOPPED(wstatus):若子进程是被信号暂停(仅在使用WUNTRACED标志或子进程被跟踪时有效),则返回true;
WSTOPSIG(wstatus):仅当WIFSTOPPED为true时使用,返回导致子进程暂停的信号编号(如19对应SIGSTOP);
子进程被恢复运行:
WIFCONTINUED(wstatus):若子进程是通过SIGCONT信号恢复运行,则返回true;
3.waitpid函数
| 所需头文件 |
#include <sys/types.h> #include <sys/wait.h> |
|
| 原型 | pid_twaitpid(pid_t pid,int *wstatus,int options); | |
| 功能 |
父进程等待子进程状态变化并获取其状态信息 允许父进程精准控制子进程的范围,可通过options调整等待行为(如阻塞 / 非阻塞) |
|
| 参数 | PID |
指定要等待的子进程 <-1:等待任何进程组id于进程pid相等的绝对值的子进程 -1:等待任何子进程资源 0:等待任何进程组id与调用进程相同的进程 >0: 等待指定pid的子进程 |
| wstatus |
用于存储子进程的退出状态值的内存空间首地址 wstatus若为空(NULL),表示忽略子进程退出时的状态 wstatus若不为空,表示将子进程退出状态写入该指针指向的内存,供父进程后续用宏解析 |
|
| options | 标志位(默认模式是阻塞等待模式 options = 0) | |
| 返回值 |
成功返回终止子进程的PID 如果设置非阻塞且没有子进程退出,会返回0 如果调用进程没有子进程或者是调用出错,返回-1.同时会会设置reeno来指示错误原因 |
|
代码示例:
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc ,const char*argv[])
{
//创建函数
pid_t pid = fork();
if(pid == -1)
{
perror("创建子进程失败\n");
return -1;
}
else if(pid == 0)
{
//子进程
while(1)
{
printf("我是子进程\n");
sleep(1);
exit(EXIT_SUCCESS);// //子进程正常退出
}
}
else if(pid > 0)
{
//父进程
while(1)
{
printf("我是父进程\n");
sleep(1);
//等待子进程退出
//第一个参数用于指定要等待的子进程,-1表示等待任意子进程退出
//第二个参数用于指定字子进程的退出状态值的存放空间
//NULL代表不关注子进程的退出状态值
//第三个参数用于指定等待的方式,0:表示是阻塞等待方式
//pid_t waitpid_ret = waitpid(-1,NULL,0);
//关注子进程的退出状态值
int st = 0;//保存子进程的退出状态值
pid_t waitpid_ret = waitpid(-1,&st,0);
if(waitpid_ret == -1)
{
perror("调用进程中没有子进程或者是调用出错\n");
return -1;
}
else if(waitpid_ret == pid)
{
printf("父进程成功等待到了子进程的退出\n");
//获取子进程的退出状态值
if(WIFEXITED(st))//正常退出
{
printf("子进程的退出状态值为%d\n",WEXITSTATUS(st));
}
else if(WIFSIGNALED(st))
{
printf("子进程非正常退出(子进程被信号终止),信号是:%d\n",WTERMSIG(st));
}
}
}
}
return 0;
}
4.options参数
| 选项常量 | 作用 | 具体行为 | 典型应用场景 |
|---|---|---|---|
| 0 | 实现阻塞等待 | 父进程暂停直到子进程状态变化 |
常规子进程同步等待(如批处理 |
| WNOHANG | 实现非阻塞等待 |
调用waitpid时,若指定子进程未退出, 函数立即返回0,父进程无需阻塞等待 |
父进程需轮询监控子进程状态 (入后台任务管理) |
| WUNTRACED | 捕获子进程暂停状态 |
当子进程因信号(如SIGSTOP)停止运行时 waitpid返回该子进程PID |
调试场景 需处理子进程暂停逻辑的程序 |
| WCONTINUED | 捕获子进程恢复运行状态 |
已停止的子进程通过SIGCONT信号恢复运行时 waitpid返回该子进程 |
需跟踪子进程完整声明周期 (暂停 - 恢复)场景 |
5.waitpid函数状态解析宏
子进程正常退出:
WIFEXITED(wstatus): 若子进程是正常终止(调用exit()/_exit()或从main()返回),则返回true;
WEXITSTATUS(wstatus): 仅当WIFEXITED为true时使用,返回子进程的退出状态码(即exit(n)中的n, 取低8位);
子进程被信号终止:
WIFSIGNALED(wstatus): 若子进程是被信号终止(如SIGKILL等), 则返回true;
WTERMSIG(wstatus): 仅当WIFSIGNALED为true时使用,返回导致子进程终止的信号编号(如9对应SIGKILL);
WCOREDUMP(wstatus): 仅当WIFSIGNALED为true时使用,若子进程终止时产生了核心转储文件,则返回true;
子进程被信号暂停:
WIFSTOPPED(wstatus): 若子进程是被信号暂停(仅在使用WUNTRACED标志或子进程被跟踪时有效),则返回true;
WSTOPSIG(wstatus): 仅当WIFSTOPPED为true时使用,返回导致子进程暂停的信号编号(如19对应SIGSTOP);
子进程被恢复运行:
WIFCONTINUED(wstatus): 若子进程是通过SIGCONT信号恢复运行,则返回true;
非阻塞模式:
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc ,const char*argv[])
{
//创建子进程 --完成:让父进程以非阻塞的方式等待子进程退出
pid_t pid = fork();
if(pid == -1)
{
perror("创建子进程失败\n");
return -1;
}
else if(pid == 0)
{
//子进程
printf("我是子进程,我开始执行...\n");
sleep(6);//延时6秒
printf("我是子进程,我执行完毕...\n");
exit(EXIT_SUCCESS);//子进程正常退出
}
else if(pid > 0)
{
//父进程
printf("我是父进程,我开始执行...\n");
while(1)
{
//父进程等待子进程的退出
//父进程在非阻塞下等待子进程的退出
//非阻塞模式本质上就是在循环轮询子进程的状态
pid_t ret = waitpid(-1,NULL,WNOHANG);
if(ret == -1)
{
perror("父进程等待子进程失败\n");
return -1;
}
else if(ret == 0)//只有在非阻塞模式下才判断返回值为0的情况
{
printf("父进程非阻塞等待子进程,子进程没有退出\n");
sleep(1);//休眠1秒再次进行检查
}
else if(ret > 0)
{
printf("父进程非阻塞等待子进程,子进程退出了\n");
break;
}
}
}
return 0;
}
阻塞模式:
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc ,const char*argv[])
{
//创建函数
pid_t pid = fork();
if(pid == -1)
{
perror("创建子进程失败\n");
return -1;
}
else if(pid == 0)
{
//子进程
while(1)
{
printf("我是子进程\n");
sleep(1);
exit(EXIT_SUCCESS);// //子进程正常退出
}
}
else if(pid > 0)
{
//父进程
while(1)
{
printf("我是父进程\n");
sleep(1);
//等待子进程退出
//第一个参数用于指定要等待的子进程,-1表示等待任意子进程退出
//第二个参数用于指定字子进程的退出状态值的存放空间
//NULL代表不关注子进程的退出状态值
//第三个参数用于指定等待的方式,0:表示是阻塞等待方式
//pid_t waitpid_ret = waitpid(-1,NULL,0);
//关注子进程的退出状态值
int st = 0;//保存子进程的退出状态值
pid_t waitpid_ret = waitpid(-1,&st,0);
if(waitpid_ret == -1)
{
perror("调用进程中没有子进程或者是调用出错\n");
return -1;
}
else if(waitpid_ret == pid)
{
printf("父进程成功等待到了子进程的退出\n");
//获取子进程的退出状态值
if(WIFEXITED(st))//正常退出
{
printf("子进程的退出状态值为%d\n",WEXITSTATUS(st));
}
else if(WIFSIGNALED(st))
{
printf("子进程非正常退出(子进程被信号终止),信号是:%d\n",WTERMSIG(st));
}
}
}
}
return 0;
}
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)