1. 进程消亡
1.1 僵尸进程
进程代码执行结束,空间没有被回收
当子进程(child process)先于父进程(parent process)退出,但是父进程没有调用wait/waitpid回收子进程的资源,则子进程变成僵尸进程。
1.2 如何避免产生僵尸进程
1.让父进程先结束,子进程会成为孤儿进程,被系统进程收养,子进程结束系统进程
回收子进程空间
2.子进程结束,父进程回收子进程空间,即可避免产生僵尸进程
2. 进程空间回收函数
2.1 wait(阻塞回收)
1. 定义
pid_t wait(int *wstatus);
2. 功能
阻塞回收子进程空间(随机回收)
3. 参数
wstatus:存放子进程结束状态空间首地址
4. 返回值
成功返回回收到的子进程的PID
失败返回-1
5. 注意
wait具有阻塞功能
WIFEXITED(wstatus)——1正常退出、0异常退出
检测子进程是否正常退出
WEXITSTATUS(wstatus)——返回子进程的ID号
检测子进程退出的值
WIFSIGNALED(wstatus)——1子进程被信号杀死、0子进程没被信号杀死
检测子进程是否被信号杀死
WTERMSIG(wstatus)——返回杀死进程的信号数
检测子进程被几号信号杀死
6. 示例程序
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
pid_t ret = fork();
if (ret > 0)
{
printf("this father proc pid : %d ppid : %d\n", getpid(), getppid());
int status;
pid_t recycleid = wait(&status);
if (WIFEXITED(status))
{
printf("terminated normally, exit is %d\n", WEXITSTATUS(status));
}
else if (WIFSIGNALED(status))
{
printf("terminated by a signal, signal num is %d\n", WTERMSIG(status));
}
printf("wait recycle id %d\n", recycleid);
}
else if (0 == ret)
{
printf("this child proc pid : %d ppid : %d\n", getpid(), getppid());
sleep(10);
exit(50);
}
else
{
perror("fork error");
return -1;
}
return 0;
}
2.2 waitpid(非阻塞回收)
1. 定义
pid_t waitpid(pid_t pid, int *wstatus, int options);
2. 功能
回收子进程空间 (指定)
3. 参数
pid:
-1 回收任意一个子进程空间
>0 回收和传入PID值相同的子进程空间
wstatus:
存放子进程结束状态空间首地址
options:
WNOHANG 非阻塞回收(子进程没有退出不会阻塞等待)
0 阻塞回收
4. 返回值
成功返回回收到的子进程的PID
失败返回-1
如果WNOHANG被设置,且没有子进程结束返回0
5. 示例程序
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
pid_t ret = fork();
if(ret > 0)
{
printf("this father proc pid : %d ppid : %d\n", getpid(), getppid());
int status;
while(1)
{
pid_t recycleid = waitpid(ret ,&status,WNOHANG);
if(recycleid == ret)
{
if(WIFEXITED(status))
{
printf("terminated normally ,exit is %d\n",WEXITSTATUS(status));
}
else if (WIFSIGNALED(status))
{
printf("terminated by a signal,signal num is %d\n",WTERMSIG(status));
}
printf("wait recycle id %d\n",recycleid);
break;
}
else
{
printf("非阻塞,子进程未结束\n");
}
usleep(1000*500);
}
}
else if(0 == ret)
{
printf("this child proc pid:%d ppid:%d\n",getpid(),getppid());
sleep(10);
exit(50);
}
else
{
perror("fork error");
return -1;
}
return 0;
}
3. exec函数族
利用进程空间执行另一段代码
用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),
子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程的
用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不创建
新进程,所以调用exec前后该进程的id并未改变。
3.1 execl
int execl(const char *path, const char *arg, ...
/* (char *) NULL */);
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
// ls -l -a
execl("/bin/ls", "ls", "-l", "-a", NULL);
printf("看见就错了\n");
return 0;
}
3.2 execlp
int execlp(const char *file, const char *arg, ...
/* (char *) NULL */);
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
// ls -l -a
//echo $PATH
execlp("ls", "ls", "-l", "-a", "-h", "--color=auto", NULL);
printf("看见就错了\n");
return 0;
}
3.3 execle
int execle(const char *path, const char *arg, ...
/*, (char *) NULL, char * const envp[] */);
3.4 execv
int execv(const char *path, char *const argv[]);
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
// ls -l -a
char *const arg[] ={"ls", "-l", "-a", "-h", "--color=auto", NULL};
execv("/bin/ls", arg);
printf("看见就错了\n");
return 0;
}
3.5 execvp
int execvp(const char *file, char *const argv[]);
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
// ls -l -a
char *const arg[] ={"ls", "-l", "-a", "-h", "--color=auto", NULL};
execvp(arg[0], arg);
printf("看见就错了\n");
return 0;
}
3.6 execvpe
int execvpe(const char *file, char *const argv[],
char *const envp[]);
l:执行另一段代码参数以列表形式传递
v:执行另一段代码参数以指针数组形式传递
p:执行另一段代码文件在系统环境变量PATH对应的路径下查找
e:执行另一段代码,更新环境变量
4.getenv
char *getenv(const char *name);
功能:
获得环境变量name对应的数值
参数:
name:环境变量名
返回值:
成功返回环境变量的值
失败返回NULL
5.setenv
int setenv(const char *name, const char *value, int overwrite);
功能:
添加或者修改环境变量的值
参数:
name:环境变量名
value:环境变量的值
overwrite:是否覆盖(非0会覆盖)
返回值:
成功返回0
失败返回-1
6.system
int system(const char *command);
功能:
加载一条shell命令
参数:
command:shell命令字符串空间首地址
返回值:
成功返回执行命令的结果
失败返回-1