目录
进程的退出
在进程结束时,需要释放分配给进程的地址空间以及内核中产生的各种数据结构
资源的释放需要通过 exit 函数或者 _exit 函数来完成
在程序结束时,会自动调用 exit 函数
exit 与_exit 的区别
exit
函数头文件 #include <stdlib.h>
函数功能
结束进程,并刷新缓冲区
在系统中定义了两个状态值 : EXIT_SUCCESS 正常退出,EXIT_FAILURE 异常退出,具体定义在 stdlib.h 中
#define EXIT_FAILURE 1 /* Failing exit status. */
#define EXIT_SUCCESS 0 /* Successful exit status. */
说说 exit 的特点
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
pid_t pid = fork();
if(pid == -1)
{
perror("fork");
exit(EXIT_FAILURE);
}
else if(pid==0)
{
printf("child process <%d> is running.....\n",getpid());
sleep(2);
exit(EXIT_SUCCESS);
printf("child process <%d> ready to exit.\n",getpid());
}
else
{
sleep(5);
}
return 0;
}
说明exit函数会刷新缓冲区
_exit
_exit 函数终止进程,但不会刷新缓冲区;
其用法与exit一样
总结
_exit()属于系统调用,能够使进程停止运行,并释放空间以及销毁内核中的各种数据结构
exit()基于_exit()函数实现,属于库函数, 会自动刷新I/O缓冲区
进程的等待
在子进程运行结束后(调用exit或_exit),进程进入僵死状态,并释放资源,子进程在内核中的数据结构依然保留。可以理解为,你把一只螃蟹吃了,还剩下螃蟹壳
父进程调用wait() 与waitpid() 函数等待子进程退出后,释放子进程遗留的资源 (task_struct)
wait
函数头文件
#include <sys/types.h>
#include <sys/wait.h>
函数原型
pid_t wait(int *wstatus);
函数功能
让函数调用者进程进入到睡眠状态,等待子进程进入僵死状态后,释放相关资源并返回
函数参数
wstatus:保存子进程退出状态值变量的指针
*****获取具体值需要使用宏定义*****
返回值:
成功:返回退出子进程的pid
失败:返回-1
int main()
{
pid_t pid = fork();
if(pid == -1)
{
perror("fork");
exit(EXIT_FAILURE);
}
else if(pid==0)
{
printf("child process <%d> is running.....",getpid());
sleep(2);
//exit(EXIT_SUCCESS);
// 自定义状态值
exit(1000);
}
else
{
int status = 0;
pid_t cpid = wait(&status);
printf("The process <%d> has exit, status code:%d\n",cpid,WEXITSTATUS(status));
}
return 0;
}
wait 总结:
会阻塞调用者进程(一般为父进程)
在子进程状态变为僵死态时,回收资源,并释放资源后返回
waitpid
waitpid函数的功能与wait函数一样,但比wait()函数功能更强大,可以理解成 wait() 底层调用waitpid()函
数
函数头文件
#include <sys/types.h>
#include <sys/wait.h>
函数原型
pid_t waitpid(pid_t pid, int *wstatus, int options);
函数参数
pid:进程id
-1 可以等待任意子进程
>0 等待id为pid的进程
wstatus:保存子进程退出状态值的指针
options:选项
WNOHANG 非阻塞选项
0 阻塞式与wait等同
函数返回值
成功
>0 退出进程的pid
=0 在非阻塞模式下,没有进程退出
失败:
-1,并设置errno
总结
waitpid使用阻塞的方式等待任意子进程退出 : waitpid(-1,&status,0);
waitpid使用非阻塞的方式等待子进程退出 :while((cpid=waitpid(-1,&status,WNOHANG))==0);
如果不关心状态值,子进程退出状态值的指针为NULL;
wait(NULL);
waitpid(-1,NULL,0);
进程替换
创建一个进程后,pid 以及在内核中的信息保持不变,但进程所执行的代码进行替换。
就理解为在进程里干其他进程的事
应用场景:
Linux 终端应用程序,在执行命令时,通过创建一个进程,然后替换成对应命令的可执行程序,在
执行。
exec函数族
在 Linux 系统中提供了一组用于进程替换的函数,共有6个
int execl(const char *pathname, const char *arg, .../* (char *) NULL */);
int execlp(const char *file, const char *arg, .../* (char *) NULL */);
int execle(const char *pathname, const char *arg, .../*, (char *) NULL, char
*const envp[] */);
int execv(const char *pathname, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[],char *const envp[]);
path:可执行文件的路径名
file:可执行文件名,可以通过PATH环境变量指定的路径
arg:参数列表,以NULL结尾
argv[]:参数数组
envp[]:环境变量数组
1.execl函数执行 ls -l 命令
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
int ret;
ret = execl("/bin/ls","ls","-l",NULL);
if(ret == -1)
{
perror("execl");
return -1;
}
return 0;
}
2.通过 execlp函数执行 ls -l 命令
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
int ret;
ret = execlp("ls","ls","-l",NULL);
if(ret == -1)
{
perror("execl");
return -1;
}
printf("process replace.\n");
return 0;
}
3. 通过 execv函数执行 ls -l 命令
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
int ret;
char* params[]={"ls","-l",NULL};
ret = execv("/bin/ls",params);
if(ret == -1)
{
perror("execl");
return -1;
}
printf("process replace.\n");
return 0;
}
注意 :如果使用的是可执行文件的名称时,必须是PATH环境变量包含的路径
4. 通过 exec族函数执行另外一个程序
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
int ret;
char* params[]={"./waitassignment",NULL};
//第一个参数是 可执行程序的路径 parmas中的"./waitassignment"是执行形式
ret = execv("./waitassignment",params);
if(ret == -1)
{
perror("execl");
return -1;
}
printf("process replace.\n");
return 0;
}
exec函数族 形式差不多,掌握一两个其他都差不多