进程exec,waitpid,回调函数等 day33

八:僵尸进程和孤儿进程

僵尸进程:进程执行结束但空间(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");
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值