本文旨在分享我对Linux进程的理解和见解。由于个人知识和经验的限制,文中可能存在错误或遗漏。我真诚地邀请各位读者在阅读过程中发现任何问题时,指出错误并提供宝贵的意见。您的反馈将是我不断进步和完善的重要动力。
进程退出一共就三种情况:
_exit和exit在下文详解。

在对于退出信号可以使用 kill -l 查询,如下:

_exit是一个系统提供的接口,它的参数是一个int类型,需要传一个退出信号返回。而exit是C语言提供的接口,它同样是让程序退出,需要传一个退出信号返回。
而_exit与exit一个很大的区别就是_exit不会刷新缓冲区,而exit会刷新缓冲区,其中exit底层还是使用了_exit实现。
可以做一个简单的小测试:

注意:(1)这里程序是从exit和_exit退出的,而不是从return 0退出。(2)这里我有意在printf输出字符串后没有加\n,因为\n会让缓冲区刷新,会干扰测试。
进程等待指的是父进程等待子进程结束。
在子进程结束后它的pcb不会立马释放,而是进入僵尸状态,让父进程回收。当然如果父进程永远不来回收,那么子进程pcb就永远得不到释放,从而内存泄漏。
而父进程在等待子进程退出这个过程就叫作进程等待。
wait是一个用来进程等待的函数,使用它需要包含的头文件为 sys/types.h 和 sys/wait.h。函数声明如下:
pid_t wait(int *status);waitpid同样是一个用来进程等待的函数,它的功能要更多,使用它需要包含的头文件为 sys/types.h 和 sys/wait.h。函数声明如下:
pid_t waitpid(pid_t pid, int *status, int options);返回值:
参数:
status可以得到进程的退出码和退出信号。
它是如何同时储存退出码和退出信号呢?其实用了一个位图的思想。status是一个int类型一共占4*8个比特位。而这里用了它的低16位,如下:

所以退出码我们可以使用(status>>8)&0xFF获取,退出信号通过status&0x7F获取。当然系统给我们提供了WIFEXITED和WEXITSTATUS两个宏来做进程退出状态检查。功能如下:
阻塞等待:使用wait或使用waitpid第三个参数传0的话,父进程在等待子进程过程中,如果子进程没有结束,那么父进程就会一直等。直到子进程退出。
非阻塞等待:父进程是很忙的,当子进程没有退出的时候也不能在那里干等着。所以正如刚才所讲,waitpid第三个参数中传入WNOHANG就能实现子进程还没退出就不等,继续做自己的其他工作,这就是非阻塞等待。当然刚才没有等到子进程结束,还得找个时间再等,要不然到时候子进程pcd就不能被回收。所以如果使用WNOHANG就需要重复的waitpid,这就是非阻塞轮询。
如下是一个程序替换的程序(execl函数使用在下文会讲解):
#include<stdio.h>
#include<unistd.h>
int main()
{
execl("/usr/bin/ls","/usr/bin/ls","-la",NULL);//程序替换
printf("hello linux\n");
return 0;
}进程替换就是在一个进程执行中把该进程后续的内容替换成其他进程。要知道指令的本质就是一个可执行文件,它是用c语言写的。以上代码就相当于把ls这个程序的代码把后面的原代码覆盖掉,所以其中pcd,虚拟地址空间,页表并没有改变,而是物理内存改变了。
注意:(1)进程替换并不会有新的进程生成。(2)进程替换可以替换为任何进程,无论是什么语言,打个比方就是说,x写的程序,在执行过程中可以替换成y写的程序(x,y表示任意语言)。
如下是一个exec函数族,即程序替换函数族:
#include <unistd.h>
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ...,char *const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execve(const char *path, char *const argv[], char *const envp[]);替换一个程序起码要知道这个程序的路径吧?需要知道它的名字吧?还需要知道命令行参数吧?
上面函数的命名特点如下:
这些exec族的返回规则是一样的,如果执行成功没有返回值,如果调用失败返回-1。
非常感谢您能耐心读完这篇文章。倘若您从中有所收获,还望多多支持呀!
以下代码是对该篇文章知识的应用:
#include<stdio.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
#include<errno.h>
#include<stdlib.h>
#include<string.h>
char* const g_argev1[]=
{(char* const)"/usr/bin/ls",
(char* const)"-a",
(char* const)"-l",
NULL};
char* const g_argev2[]=
{(char* const)"ls",
(char* const)"-a",
(char* const)"-l",
NULL};
char* const env[]= //这里的环境变量是随便设的没有实际的意义,只是为了说明问题
{(char* const)"HPP=128",
(char* const)"GHH=29",
(char* const)"p=..",
NULL};
int main()
{
pid_t id=fork();
if(id==0)
{
execl("/usr/bin/ls","ls","-l","-a",NULL);
//execv(g_argev1[0],g_argev1);
//execlp("ls","-ln","-a",NULL);
//execvp(g_argev2[0],g_argev2);
//execle("./code","ls","-l","-a",NULL,env);
//execve(g_argev1[0],g_argev2,env);
exit(1); // 如果所有exec都失败,则执行到这里
}
int status;
pid_t p=waitpid(id,&status,0);
if(p>0)
{
if(WIFEXITED(status))
printf("exit code:%d, exit signal:%d\n",WEXITSTATUS(status),status&0x7F);
// 注意:status&0x7F 用于获取终止信号,但通常我们只关心 WEXITSTATUS(status)
else
printf("程序执行异常\n");
}
else
printf("waitpid fail:%s",strerror(errno));
return 0;
}