八:僵尸进程和孤儿进程
僵尸进程:进程执行结束但空间(pcb块)未被回收变成僵尸进程
九:回调函数atexit
int atexit(void (*function)(void));
//atexit - register a function to be called at normal process termi‐nation
//是注册,不是直接调用,是到时候到程序结束时,检测一下有没有调atexit
功能: 注册进程退出前执行的函数
参数: function: 函数指针 指向void返回值void参数的函数指针
返回值: 成功返回0
失败返回非0
当程序调用exit或者由main函数执行return时,所有用atexit
注册的退出函数,将会由注册时顺序倒序被调用
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
int fd;
char *p;
void clean()
{
printf("this is clean,p: %s,fd: %d\n",p,fd);
free(p);
close(fd);
}
int main(int argc, char **argv)
{
atexit(clean);
p = (char*)malloc(10);
fd = open("log",O_RDONLY);
printf("in procing..\n");
strcpy(p, "hello");
char buf[10] = {0};
read(fd, buf, 10);
printf("before return 0\n");
//system("pause");
return 0;
}
--------------------------------------------------
in procing..
before return 0
this is clean,p: hello,fd: -1
9.1主动调用和被动调用
atexit(clean);//被动调用,程序流程结束后自动触发
atexit(clean());//主动调用,只在调用时执行;不会在程序结束时自动调用。
十:进程空间的回收,wait/waitpid
pid_t wait(int *status); //等待退出状态(本质上也是等待什么样的信号,不止退出信号)
//wait, waitpid, waitid - wait for process to change state
//什么状态都能捕获
功能:该函数可以阻塞等待任意子进程退出,并回收该进程的状态。
一般用于父进程回收子进程状态。
参数:status 进程退出时候的状态
如果不关心其退出状态一般用NULL表示
如果要回收进程退出状态,则用WEXITSTATUS回收。
返回值:成功 回收的子进程pid,
失败 -1;
int main(int argc, char **argv)
{
pid_t pid = fork();
if(pid > 0)
{
printf("father,id:%d\n",getpid());
wait(NULL);
printf("recycle end...\n");
}else if (0 == pid)
{
sleep(3);
printf("child id:%d\n",getpid());
exit(1);//正常退出,检查之前的wait
}else
{
perror("fork");
return -1;
}
//system("pause");
return 0;
}
--------------------------------------------------
father,id:10319
child id:10320
recycle end...
十一:wait的宏
WIFEXITED(wstatus) //Wait If Exited —— 子进程是否是“正常退出”
returns true if the child terminated normally, that is, by
calling exit(3) or _exit(2), or by returning from main().
WEXITSTATUS(wstatus) //Wait Exit Status(等待退出状态宏)
returns the exit status of the child. This consists of the
least significant 8 bits of the status argument that the
child specified in a call to exit(3) or _exit(2) or as the
argument for a return statement in main(). This macro
should be employed only if WIFEXITED returned true.
WIFSIGNALED(wstatus) // Wait If Signaled —— 等待结果中是否“被信号终止
returns true if the child process was terminated by a sig‐
nal.
WTERMSIG(wstatus) //获取导致子进程异常终止的信号编号,一般配合 WIFSIGNALED(status) 一起使用。
returns the number of the signal that caused the child
process to terminate. This macro should be employed only
if WIFSIGNALED returned true.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
pid_t pid = fork();
if(pid>0)
{
printf("father ,id:%d\n",getpid());
int status; //退出状态
pid_t pid2 = wait(&status);//block 阻塞
if(WIFEXITED(status)) //是不是正常结束
{ //在退出状态中,取出 退出值
printf("child normal terminal... ,exit val %d\n",WEXITSTATUS(status));
}
if(WIFSIGNALED(status)) //是不是异常结束,信号导致的
{
printf("terminal by signal ,signal num:%d\n",WTERMSIG(status));
}
printf("recycle end... pid2 is %d\n",pid2);
}
else if (0 == pid)
{
printf("child id:%d\n",getpid());
sleep(10);
exit(20);
}
else
{
perror("fork");
return 1;
}
return 0;
}
十二:pid_t wait
pid_t wait(int *wstatus);
pid_t waitpid(pid_t pid, int *wstatus, int options);
int waitid(idtype_t idtype, id_t id, siginfo_t *infop,int options);
1)如果所有的子进程都在运行,在阻塞
2)如果一个子进程终止,正在等待的父进程则获得终止状态,获得子进程的状态后,立刻返回。
3)如果没有子进程,则立即出错退出。
waitpid(-1,status,0)=wait(status);
pid_t waitpid(pid_t pid, int *status, int options);
< -1 回收指定进程组内的任意子进程
-1 回收任意子进程,组内外
0 回收和当前调用waitpid一个组的所有子进程,组内
> 0 回收指定ID的子进程
waitpid (-1,a,0) == wait(a);
status 子进程退出时候的状态,
如果不关注退出状态用NULL;
options 选项:
0 表示回收过程会阻塞等待
WNOHANG 表示非阻塞模式回收资源。
返回值:成功 返回接收资源的子进程pid
失败 -1
0,
//用非阻塞回收指定子进程
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char **argv)
{
int want_n = 3;
int i = 0 ;
pid_t pid[5]={0};
for(i = 0;i<5;i++)
{
pid[i]= fork();
if(pid[i]>0)
{
}
else if(0 == pid[i])
{
printf("child ,pid:%d\n",getpid());
sleep(rand()%5+1);
exit(1);
}
else
{
perror("fork");
return 1;
}
}
while(1)
{
pid_t recycle_pid = waitpid(pid[want_n-1],NULL,WNOHANG);
if(recycle_pid == pid[want_n-1])
{
printf("recycle pid :%d\n",recycle_pid);
break;
}
if(0 == recycle_pid)
{
// printf("继续努力\n");
}
if(-1 == recycle_pid)
{
printf("子进程id 错误\n");
break;
}
}
//system("pause");
return 0;
}
十三:exec
exec(execute)族
execute a file
用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),
子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程的
用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不创建
新进程,所以调用exec前后该进程的id并未改变。
其实有六种以exec开头的函数,统称exec函数:但是功能都一样,参数不同
✨ fork:一个变两个
✨ exec:换芯不换壳(换程序不换进程)
✨ fork + exec:父子分家,子改命运 //exec+fork 不会产生新的子进程
//exec 不会创建新的子进程,它只是用另一个程序“替换”当前进程的内容,PID 不变,也不会有多一个子进程产生。
//调用 exec 成功后,后面的代码不会再执行。
int execl(const char *path, const char *arg, .../* (char *) NULL */);
int execlp(const char *file, const char *arg, .../* (char *) NULL */);
int execle(const char *path, const char *arg, ... /*, (char *) NULL, char * const envp[] */);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[],char *const envp[]);
实现ll命令
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char **argv)
{
printf("argc is %d\n",argc);
int i = 0 ;
for(i = 0;i<argc;i++)
{
printf("%d %s\n",i,argv[i]);
}
//system("pause");
return 0;
}
-------------------------------------------------------------------
gcc test.c -o aaa
//要想直接稳妥写法,就全写*file的写法,把路径写全了(路径+文件名)
一:execl
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char **argv)
{
//ls -a -l
// ./a.out -a -l execute argument list
execl("/bin/ls","ls","-a","-l","--color=auto",NULL);
//firefox www.baidu.com
// execl("/usr/bin/firefox","firefox","www.baidu.com",NULL);
printf("看见就错了\n");
//system("pause");
return 0;
}
// execl("/usr/bin/firefox","firefox","www.baidu.com",NULL);
execl("aaa","firefox","www.baidu.com",NULL);
printf("看见就错了\n");
二:execlp
//p-----PATH,环境变量,系统变量,路径
echo $PATH
-----------------------------------------------------------
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/home/linux/tools/opt/FriendlyARM/toolschain/4.4.3/bin
int main(int argc, char **argv)
{
execlp("cat", "cat","13execlp.c",NULL);//PATH 也可以使用绝对路径
printf("you see you wrong\n");
//system("pause");
return 0;
}
// execlp("ls","ls","-a","-l","--color=auto",NULL);
execlp("/home/linux/proc/day_01/aaa","ls","-a","-l","--color=auto",NULL);
printf("看见就错了\n");
三:execv
char *const args[] = {"ls","-a","-l","--color=auto",NULL};
execv("/bin/ls",args);//vector 数组
printf("看见就错了\n");
char *const args[] = {"aaa","1","2","--color=auto",NULL};
// execv("/bin/ls",args);//vector 数组
execv("aaa",args);
printf("看见就错了\n");
四:execvp
char *const args[] = {"ls", "-a", "-l", "--color=auto", NULL};
// execv("/bin/ls",args);//vector 数组
execvp(args[0], args);
char *const args[] = {"/home/linux/proc/day_01/aaa", "aaa", "1", "--color=auto", NULL};
// execv("/bin/ls",args);//vector 数组
execvp(args[0], args);
printf("看见就错了\n");

被折叠的 条评论
为什么被折叠?



