进程的相关操作
main函数返回值:返回给操作系统
echo $?
进程退出码:进程退出时的返回值
0:正常退出
!0:退出异常
各个退出码所对应的各个文字信息,例如下面:
#include<stdio.h>
#include<string.h>
int main()
{
for(int i=0;i<100;i++)
{
printf("%d:%s\n",i,strerror(i));
}
return 0;
}
进程等待:
为了回收子进程资源,获得子进程退出信息
如果子进程退出了,而父进程没有回收子进程的资源,对子进程不管不顾,那么子进程就会变成僵尸进程,就算是kill -9也无法杀死,,所以必须对子进程资源进行回收,而这个回收工作通常由父进程来完成,父进程完成子进程资源回收的这个过程叫做进程等待
关于子进程资源回收我们经常用wait/waitpid进行回收
父子进程谁先运行不一定,但是在进程等待之后,子进程先退出,父进程在回收子进程资源后再退出
wait操作
pid_t wait(int status)
返回值:
返回成功返回子进程pid,失败返回-1
参数:
输出型参数,不关心设置为NULL
#include<stdio.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<stdlib.h>
#include<unistd.h>
int main()
{
pid_t id=fork();
if(id==0)
{
int count=0;
while(count<5)
{
printf("I am child ,pid:%d,ppid:%d\n",getpid(),getppid());
sleep(1);
count++;
}
exit(1);
}
else
{
int ret=wait(NULL);
if(ret>=0)
{
printf("child exit success:pid:%d\n",ret);
}
printf("Father is running\n");
sleep(5);
}
return 0;
}
wait获取子进程相关信息成功,返回子进程的pid,返回失败返回-1
waitpid(pid_t id int*status,int options),头文件是<sys/wait.h>
waitpid当正常返回时返回子进程的id,失败时返回0
阻塞等待的方式
#include<stdio.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
pid_t id=fork();
if(id==0)
{
int count=0;
while(count<5)
{
printf("I am child,pid:%d,ppid:%d\n",getpid(),getppid());
sleep(1);
count++;
}
exit(10);
}
else
{
int status=0;
pid_t ret=waitpid(id,&status,0);
if(ret>=0)
{
printf("child exit success,ret:%d\n",ret);
printf("child exit code:%d\n",(status>>8)&0xFF);
printf("child exit signal:%d\n",status&0x7F);
}
printf("Father is running\n");
sleep(5);
}
return 0;
}
等待成功,并不意味着进程运行成功了,仅仅代表着进程退出了,要看进程是否运行成功还要看进程退出时发出的信号,例:
如上所示,我们利用kill -9强行杀死子进程,但是上面依然显示等待成功,所以退出码并不能代表进程运行是否成功了,还要看退出信号
上面我们利用status来说明退出信息和退出码比较繁琐,我们一般不使用,经常使用下面这种
WIFEXITED(status):如果正常终止子进程返回的状态,则为真(查看进程是否正常退出),本质是查看信号是否正常
WEXITSTATUS(status):若WIFEXITED为真,则提取子进程的退出码(查看进程的退出码)(这时候的退出码就代表子进程正常执行执行完毕了)
#include<stdio.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
pid_t id=fork();
if(id==0)
{
int count=0;
while(count<20)
{
printf("I am child,pid:%d,ppid:%d\n",getpid(),getppid());
sleep(1);
count++;
}
exit(10);
}
else
{
int status=0;
pid_t ret=waitpid(id,&status,0);
if(WIFEXITED(status))
{
printf("child exit success\n");
printf("child exit code:%d\n",WEXITSTATUS(status));
}
else
{
printf("child exit signal:%d\n",status&0x7F);
}
printf("Father is running\n");
sleep(5);
}
return 0;
}
非阻塞等待:
父进程在等待子进程是不等待,还在做其他事情
int main()
{
pid_t id=for();
if(id==0)
{
int count=0;
while(cout<10)
{
printf("I am child,pid:%d,ppid%d",getpid(),getppid());
sleep(1);
count++;
}
exit(1);
}
while(1)
{
int status=0;
pid _t ret=waitpid(id,&status,WNOHANG);
if(ret>0)
{
printf("watit success\n");
printf("exit codfe:%d",WEXITSTATUS(staus));
break;
}
else if(ret==0)
printf("father do other thing ret:%d\n",ret);
else
{
printf("waitpid
error\n");
break;
}
}
return 0;
}
WNOHANG:
ret=waitpid(id,&status,WNOHANG);
ret==0代表等待成功,但是子进程还在执行
ret==-1等待失败
ret>0等待成功,子进程还在运行
ret==0,当前子进程还没有退出
进程替换
用fork创建子进程后执行的是和父进程相同的程序(但是可能执行不同的代码分支),子进程往往要调用一种exec函数以执行另一个程序,当进程调用一种exec函数时,该进程的用户空间的代码和数据就会被新程序替换,从新程序的启动例程开始执行,调用exec并不会创建心得进程,只是发生了进程替换,所以调用exec前后该进程的id并未发生变化
替换函数
#include<unistd.h>
execl("/usr/bin/ls","ls","-al",NULL);
execlp("ls","ls","-a","-l",NULL);
char*envp[]={"/usr/bin/ls",NULL};
execle("ls","ls","-a","-l",NULL,envp);
char*argv[]={"ls","-l","-a",NULL};
execv("/usr/bin/ls",argv);
execvp(“ls”,argv);
execve("/usr/bin/ls",argv,envp);
函数理解:
这些函数如果调用成功则加载新的程序从开始代码开始执行,不在返回
如果调用出错返回-1
所以exec函数只有出错时的返回值而没有成功是的返回值
命名规则:(exec+后缀)
l:代表列表,将所有选项列出来,需要自己写路径,
execl("usr/bin/ls","ls","-a","-l",NULL);
p:代表环境变量,也就是可以不用写环境变量
execlp("ls","ls","-a","-l",NULL);
e:envp表示自己配置环境变量,将环境变量保存到数组中
char*envp[]={"/usr/bin/ls",NULL};
execle("ls","ls","-a","-l",envp);
v:代表参数用数组
char*argv[]={"ls","ls","-a","-l",NULL};
execv("usr/bin/ls",argv);
vp:有环境变量了
char*argv[]={"ls","ls","-a","-l",NULL};
execvp(argv);
ve:带e,需要自己写全路径
execve("/bin/ls",argv,envp);
ps:通过替换函数我们可以将两个不同类型的程序相连接,exec函数可以连接,c++,python,java等语言所写的程序
简易shell的实现 本质是通过exec系列函数实现系统接口的调用
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<sys/types.h>
#define Len 1021
int main()
{
char cmd[Len];
while(1)
{
printf("sjw@iZ2zedu4njy79sqivntvprZ test_9_29_execl$");
fgets(cmd,Len,stdin);
cmd[strlen(cmd)-1]='\0';
char *myargv[Len];
pid_t id=fork();
int i=1;
myargv[0]=strtok(cmd," ");
while(myargv[i]=strtok (NULL," "))
{
i++;
}
if(id==0)
{
execvp(myargv[0],myarg);
exit(1);
}
else
{
int status=0;
pid _t ret=waitpid(id,&status,0);
id(WIFEXITED(status))
{
printf("exit code:%d\n",WEXITSTATUS(status));
}
}
}
return 0;
}
|