linux C孤儿进程以及进程回收

  • 上机环境linux mint下 Qt5.11
  • 一例孤儿进程代码的演示
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<fcntl.h>
int main()
{
    pid_t pid;
    pid =fork();
    if(pid==0)
    {
        while(1)
        {
            printf("i'm child=%d, parent=%d\n",getpid(),getppid());
            sleep(1);
        }
    }
    else if(pid==-1)
    {
        perror("process failed!");
        exit(1);
    }
    else
    {
        printf("i'm the master process %d\n",getpid());
        sleep(10);
        printf("master process %d died\n",getpid());
    }
    return 0;
}

输出结果:

 

由此可见,进程13345的父进程结束后,变为孤儿进程,其父进程转为1365

  • 给僵尸进程下的定义
子进程结束时,父进程会受到SIGCHILD信号。如果没有收到,也没有执行wait()子进程,那么子进程虽然终止,但还是会在内核中占有表项(PCB依然存在),此时子进程就被称作僵尸进程
  • 避免僵尸进程的方法
父进程要处理SIGCHILD信号忽略(忽略也是种处理哦)或者捕捉它,或者等待子进程结束。
如果父进程先于子进程结束,那么子进程的终止将转交给init进程处理

 

  • waitpid((int)子进程号,(int)状态码,阻塞模式)
#include <stdio.h>
#include<sys/wait.h>
#include<stdlib.h>
#include<signal.h>
#include<unistd.h>

int main()
{
    pid_t pid;
    int status;
    int retval;
    pid=fork();
    if(pid==-1)
    {
        perror("fork");
        exit(EXIT_FAILURE);
    }
    else if(pid==0)
    {
        puts("child process launched\n");
        sleep(3000);
        exit(EXIT_SUCCESS);
    }
    else{
        if(waitpid(pid,&status,WNOHANG)==0)//exit process without block
        {
            retval=kill(pid,SIGKILL);//跟信号有关的系统调用,一如kill
            if(retval)
            {
                puts("kill failed");
                perror("failed");
            }
            else
            {
                printf("%d has been killed\n",pid);
            }
        }
    }
}
  • waitpid函数第一个参数取值范围详解
关键词:等待回收
pid<-1 如果子进程的组进程号是pid的绝对值,那么这些子进程都会被父进程等待回收
pid=-1等待任何子进程相当于wait()
pid=0进程组码与目前进程相同的子进程
pid>0识别码为pid的子进程

 

  • sigaction
   struct sigaction
      {
          void (*sa_handler)(int);//信号处理函数1
          void(*sa_sigaction)(int,siginfo_t *,void*);//信号处理函数2
          sigset_t sa_mask;//信号处理函数执行期间需要屏蔽的信号,确保该信号不会再发生,例如正在处理信号A,如果又收到信号A,那么视同就是当前处理的这个新号A,这时,新到的信号A放入进程的信号掩码sa_mask
          int sa_flags;//指定信号处理行为,当包含SA_SIGINFO时,使用该系处理函数,否则使用SA_HANDLER系列处理函数
          void (*sa_restorer)(void);//已废弃不再使用,仅仅用作占位
      }
  • sa_flags  是下列信号处理行为的“按位或”组合
SA_START 被信号打断的系统调用重新发起
SA_NOCLDSTOP父进程在他的子进程暂停或继续运行时不会收到SIGCHILD信号
SA_NOCLDWAIT使父进程在子进程退出时不会收到SIGCHILD信号,这种情况下子进程不会成为僵尸进程
SA_NODEFER对信号的屏蔽无效,在信号处理期间仍能发出这个新号
SA_SIGINFO使用sa_sigaction而不是sa_handler作为信号处理函数
  • 用例:sigaction函数,使用SA_HANDLER方法---这意味着,我们使用自定义的函数来处理信号
  • 自定义信号处理函数sig_usr
static void sig_usr(int signum)
{
    if(signum==SIGUSR1)
    {
        puts("sigusr1 received\n");
    }
    else if(signum==SIGUSR2)
    {
        puts("sigusr2 received\n");
    }
    else
    {
        puts("bad luck!\n");
    }
}
  • 主函数调用
int main()
{
    int n;//n用于返回read()调用后的返回值
    struct sigaction sa_method;
    char buf[512];//栈上声明个字符数组变量,用于存放输入的命令
    sa_method.sa_flags=0;
    sa_method.sa_handler=sig_usr;//表示使用自定义的信号处理函数
    //SIGUSR1 SIGUSR2是系统预留给程序员玩的两个信号
    sigaction(SIGUSR1,&sa_method,NULL);
    sigaction(SIGUSR2,&sa_method,NULL);
    printf("当前进程号是:%d\n",getpid());
    while(1)
    {
        //读取文件描述符STDIN_FILENO
     //耐人寻味的read用法,参数一是要读取的文件描述符,参数二是要读取的数据类型大小,代码中的buf是字符数组的首元素大小,511是指一次最多可以读取511个首元素大小的量
        if((n=read(STDIN_FILENO,buf,511))==-1)//n如果大于0,是返回读取的字节数,-1代表读取失败,0代表没有读取到任何东西
        {
            if(errno==EINTR)
            {
                printf("读取出现问题,被信号中断 \n");
            }
        }
        else
        {
            buf[n]='\0';
            printf("%d bytes read: %s\n",n,buf);
        }
    }
     return 0;

}

运行过程

 

 使用SIGUSR1对进程进行扰断

 

 

 结果

 

 运行过程2

 

 使用SIGUSR2扰断

 

结果

posted @ 2020-01-12 13:24  saintdingtheGreat  阅读(703)  评论(0编辑  收藏  举报