进程的回收
1.wait
原型
pid_t wait(int *status);
功能:该函数可以阻塞等待任意子进程退出
并回收该进程的状态。
一般用于父进程回收子进程状态。
参数:status 进程退出时候的状态
如果不关心其退出状态一般用NULL表示
如果要回收进程退出状态,则用WEXITSTATUS回收。
返回值:
成功时,wait
返回终止子进程的PID。
失败时,返回-1,并设置errno
来指示错误。
关于子进程状态的一些宏定义:
1.WIFEXITED(status) 是不是正常结束,如果返回非零值,则表示子进程正常结束了它的main
函数,或者调用了exit()
函数。
2.WEXITSTATUS(status) 为真时,使用这个宏来获取子进程的退出状态码。状态码是由main
函数的返回值或者exit()
函数的参数决定的。
3.WIFSIGNALED(status) 检查子进程是否是因为接收到信号而终止的。如果返回非零值,则表示子进程是因为信号而终止。
4.WTERMSIG(status) 为真时,使用这个宏来获取导致子进程终止的信号编号。
5.WIFSTOPPED(status)
: 检查子进程是否因为接收到SIGSTOP
、SIGTSTP
、SIGTTIN
或SIGTTOU
信号而停止。如果返回非零值,则表示子进程已经停止。
6.WSTOPSIG(status)
: 当WIFSTOPPED(status)
为真时,使用这个宏来获取导致子进程停止的信号编号。
7.WIFCONTINUED(status)
: 检查子进程是否已经从停止(stopped)状态继续执行。如果返回非零值,则表示子进程已经继续。
举例:
int a=20;
int main(int argc, const char *argv[])
{
pid_t ret =fork();
if(ret>0)
{
//
printf("father is %d pid= %d,ppid= %d \n",a,getpid(),getppid());
wait(NULL);
printf("after wait\n");
sleep(5);
}
else if(0==ret)
{
printf("child = %d pid:%d ppid:%d",a,getpid(),getppid());
sleep(3);
printf("child terminal\n");
exit(1);
}
else
{
perror("fork");
return 1;
}
printf("a:%d pid:%d",a,getpid());
return 0;
}
利用宏定义,判断子进程的状态
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
int a = 20;
int main(int argc, char *argv[])
{
pid_t ret = fork();
if(ret>0)
{
//father
printf("father is %d pid %d ,ppid:%d \n",a,getpid(),getppid());
int status;
pid_t pid = wait(&status);
if(WIFEXITED(status))// 代表子进程正常结束
{
//正常结束的子进程,才能获得退出值
printf("child quit values %d\n",WEXITSTATUS(status));
}
if(WIFSIGNALED(status))//异常结束
{
printf("child unnormal signal num %d\n", WTERMSIG(status));
}
printf("after wait, %d\n",status);
}
else if(0 == ret)
{
//child
printf("child a is %d pid:%d ppid:%d\n",a,getpid(),getppid());
sleep(5);
printf("child terminal\n");
exit(50);
}
else
{
perror("fork error\n");
return 1;
}
printf("a is %d pid:%d\n",a,getpid());
return 0;
}
2.waitpid
原型
#include <sys/types.h>
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int *status, int options);
参数说明:
pid
: 子进程的PID。如果设置为-1
,则表示等待任一子进程,这与wait
函数的行为相同。status
: 指向整数的指针,用于接收子进程的状态信息。如果不需要状态信息,可以传递NULL
。options
: 指定等待行为的选项,常用的选项有:WNOHANG
: 如果子进程尚未终止,调用立即返回,而不是挂起等待。- 0: 表示回收过程会阻塞等待
返回值:
- 成功时,返回子进程的PID。
- 如果子进程尚未终止(使用了
WNOHANG
选项),返回 0。 - 失败时,返回 -1,并设置
errno
以指示错误
练习:
设计一个多进程程序,用waitpid函数指定回收
其中的某个进程资源并将其状态打印输出。
其他的进程都以非阻塞方式进行资源回收。
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int i = 0 ;
pid_t ret[5]={0};
printf("father pid %d ,ppid:%d \n",getpid(),getppid());
for(i = 0 ;i<5;i++)
{
ret[i] = fork();
if(ret[i]>0)
{
//father
}
else if(0 == ret[i])
{
//child
printf("child pid:%d ppid:%d\n",getpid(),getppid());
sleep(rand()%5);
exit(1);
}
else
{
perror("fork error\n");
return 1;
}
}
int status;
while(1)
{
pid_t pid = waitpid(ret[2],&status, WNOHANG);
if(ret[2] == pid)
{
if(WIFEXITED(status))// 代表子进程正常结束
{
//正常结束的子进程,才能获得退出值
printf("child quit values %d\n",WEXITSTATUS(status));
}
if(WIFSIGNALED(status))//异常结束
{
printf("child unnormal signal num %d\n", WTERMSIG(status));
}
printf("father recycle success, pid :%d\n",pid);
break;
}
else if(0 == pid)
{
printf("子进程未结束,稍后在试\n");
//usleep(1000);
sleep(1);
}
}
printf("after wait, %d\n",status);
return 0;
}
exec
exec函数族在 C 语言中用于在当前进程的上下文中执行一个新的程序。exec
函数不会创建新的进程,而是替换当前进程的映像为新程序的映像。这意味着进程的PID保持不变,但是执行的程序完全改变。
exec族函数
-
加载并执行由execl(const char *path, const char *arg0, ...)
:path
指定的程序,arg0
是传递给新程序的主参数,后面可以跟随其他参数,以NULL
结尾。 -
加载并执行由execv(const char *path, char *const argv[])
:path
指定的程序,argv
是一个以NULL
结尾的参数数组。 -
与execle(
const char *path, const char *arg0, ..., char *const envp[])
:execl
类似,但允许指定一个新的环境指针数组envp
,替换当前环境。 -
加载并执行由execve
(const char *path, char *const argv[], char *const envp[])
:path
指定的程序,argv
是参数数组,envp
是环境变量数组。 -
与execlp(const char *file, const char *arg0, ...)
:execl
类似,但在 PATH 环境变量中搜索程序file
。 -
与execvp(const char *file, char *const argv[])
:execv
类似,但在 PATH 环境变量中搜索程序file
。 -
与execvpe
(const char *file, char *const argv[], char *const envp[])
:execve
类似,但在 PATH 环境变量中搜索程序file
,并允许指定新的环境变量数组envp
。
举例:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
// firefox www.baidu.com
//execl("/usr/bin/firefox","firefox","www.baidu.com",NULL);
// env echo $PATH ls -l --color=auto ll
//execlp("ls","ls","-l","--color=auto",NULL);
char *const args[]={"ls","-l","--color=auto",NULL};
//execv("/bin/ls",args);//vector
// path
execvp(args[0],args);//vector+path
printf("看见就错了\n");
exit(1);
return 0;
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
// firefox www.baidu.com
//execl("./aaa","aaa","1","2","3",NULL);
// env echo $PATH ls -l --color=auto ll
//execlp("./aaa","aaa","1","2","3",NULL);
char *const args[]={"aaa","1","2","3",NULL};
//execv("./aaa",args);//vector
// path
execvp("./aaa",args);//vector+patha
//如果需要都能调用成功,第一个参数都传 路径+文件名
printf("看见就错了\n");
exit(1);
return 0;
}