zoukankan      html  css  js  c++  java
  • 11进程控制2

    同步父子进程 wait
    <sys/wait.h>
    pid_t wait(int *pState)
    无子进程则马上返回,有子进程则等待(阻塞)。多个子进程,需要多个调用
    获取子进程 pid 和 结束状态
    第一字节: *pState & 0xff--------接受到的信号值
    第二字节: (*pState >> 8) & 0xff-------退出码
    第三四字节保留:0


    同步父子进程 waitpid
    waitpid(pid_t pid, int *pState, int option)

    参数解析:
    pid
    >0 等待特定子进程
    =0 等待父进程对应进程组的所有子进程(任意一个触发退出)
    =-1 等待任意子进程
    <-1 等待进程组标志为 绝对值|pid| 的所有子进程


    option
    0------有子进程则阻塞,等待子进程结束
    1[WNOHANG]-----非阻塞调用,立即返回(wait no hang),搜集已经退出的子进程,如果要搜集多个子进程的,需要多次调用
    2[WUNTRACED]----有子进程则阻塞,但是如果waitpid之前有子进程退出,则搜集已退出的子进程并返回

    同步进程
    pid = waitpid(-1, pState, 0) 等价于
    pid = wait(pState)
    都可以搜集已经退出的子进程

    例子:
    void testWait()
    {
      pid_t pid1,pid2;
      printf("start fork:%d ",getpid());

      pid1=fork();
      if(pid1==0)
      {
        printf("this is child1 [%d] ",getpid());
        exit(1);
      }
      pid2=fork();
      if(pid2==0)
      {
        printf("this is child2 [%d] ",getpid());
        exit(2);
      }

      int state;
      pid_t pid=wait(&state);
      if(pid>0)
      {
        printf("Signal:%d,Exit:%d ",state&0xff,(state>>8)&0xff);
      }
      //多个子进程,多个wait
      wait(NULL);
      printf("end fork :%d ",getpid());
    }

    kill 杀死进程
    shell 命令
    kill –l 查看kill 信号
    kill -[sig] pid 结束程序

    函数命令
    int kill(pid_t pid, int sig)

    如:
    kill 4000(进程号)
    kill -9(信号) 4000(进程号)
    例子:
    void testKill()
    {
      pid_t pid1,pid2;
      pid1=fork();
      if(pid1==0)
      {
        pid2=fork();
        if(pid2==0)
        {
          printf("kill parent! ");
          kill(getppid(),9);
          exit(0);
        }
        else
        {
          sleep(1);
        }
       exit(0);
      }
      int state;
      pid_t pid=wait(&state);
      if(pid>0)
      {
        printf("Signal:%d,Exit:%d ",state&0xff,(state>>8)&0xff);
      }


    补充:
    sleep(N) //睡眠N秒钟
    usleep(N) //睡眠N微秒 (1秒=1000毫秒 = 10^6微秒)


    僵尸进程
    概念:
    进程已经终止,但是没有从进程表内删除。僵尸进程已经终止,所以不能接受 kill 信号
    产生原因:
    子进程终止时,会释放资源,并发送SIGCHLD信号通知父进程; 父进程接受到信号后调用wait返回子进程状态,并且释放进程表资源
    如果子进程结束时,父进程没有调用wait接受子进程信息,则子进程转化为僵尸进程,父进程退出时,僵尸进程自动结束

    例子:
    void testZomb()
    {
      pid_t pid=fork();
      if(pid==0)
      {
        printf("this is a child :%d",getpid());
        exit(0);
      }
      else
      {
        printf("this is a parent :%d",getpid());
        while(1);
      }
    }

    rowe 3440 3110 92 23:04 pts/0 00:00:08 ./main
    rowe 3441 3440 0 23:04 pts/0 00:00:00 [main] <defunct>

    <defunct>说明就是僵尸进程,并且无法使用kill命令进行终止,也无法对其进行任何操作。

    僵尸进程解决方案
    1: wait方法 (缺点:父进程阻塞)
    2:托管
    父进程先于子进程退出,则它的子进程由init进程领养,子进程的父进程ID变为1,由init释放进程表资源.
    托管技巧:fork出子进程后,在子进程中再次fork,然后退出子进程,则子子进程会被init托管,由init释放资源表
    3:忽略SIGCHLD信号
    父进程设置忽略 SIGCHLD信号,子进程结束自动释放进程表资源
    忽略SIGCHLD信号:
    signal(SIGCHLD, SIG_IGN)
    4:捕获SIGCHLD信号
    父进程捕获SIGCHLD信号,并在捕获函数代码中 执行wait()
    处理SIGCHLD信号:
    void pFun(int nSignal)
    signal(SIGCHIL, pFun)

    wait方法:
    void testZomb()
    {
      pid_t pid=fork();
      if(pid==0)
      {
        printf("this is a child :%d",getpid());
        exit(0);
      }
      else
      {
        printf("this is a parent :%d",getpid());
        wait(NULL);
        while(1);
      }
    }


    托管方法:
    void testTrust()
    {
      pid_t pid=fork();
      if(pid==0)
      {
        printf("this is a child :%d ",getpid());
        pid_t pidd=fork();
        if(pidd==0)
        {
        printf("this is a sub child :%d ",getpid());
        //可以其他操纵
        //exec()...............
        //退出子子进程
        exit(0);
        }
        else
        {
          //退出子进程
          exit(0);
        }
      }
      else
      {
      //回收资源表,父进程退出
      wait(NULL);
      printf("this is a parent :%d ",getpid());
      while(1);
      }
    }

    守护进程 daemon,也称精灵进程:是一种运行在后台的特殊进程,不存在控制终端,周期性处理某项任务,守护系统正常运行,大部分socket通信服务程序都以守护进程方式执行。
    以超级用户启动的(uid=0)
    父进程为 init (ppid=1)
    无控制终端 (tty = ?)
    终端进程组为 -1 (TPGID=-1)


    守护进程 daemon 创建步骤
    1: 后台运行
    拖管法,fork子进程后,父进程退出
    2: 脱离控制终端(伪终端)
    pid = setsid()
    创建一个新的session和进程组;
    并使用进程ID作为进程组ID,返回进程组ID / 失败返回(-1)
    3: 把当前工作目录更改为 /
    防止对当前目录的某些操作不能执行, chdir()
    4: 关闭文件描述符,重定向 stdin stdout stderr
    fd=open(“/dev/null”, O_RDWR, 0);
    dup2(fd, STDIN_FILENO); ...
    5: 设置/清除文件创建掩码 <sys/stat.h>
    umask(XXX) 可以设置进程创建的临时文件不被其他用户查看
    umask(0) 清除从父进程继承的文件创建掩码

    例子:
    void testDaemon()
    {
      pid_t pid=fork();
      //step1:托管,退出父进程
      if(pid>0)
      {
        exit(0);
      }
      //step2:脱离终端
      pid=setsid();
      //step:更改目录,可省略
      //chdir("/home");
      //step4 关闭文件描述符
      close(STDIN_FILENO);
      close(STDOUT_FILENO);
      close(STDERR_FILENO);

      //利用子进程打开文件
      pid=fork();
      if(pid==0)
      {
        //gedit代表文本编辑器,123.txt自拟文本
        execlp("gedit","gedit","123.txt",NULL);
      }
      //execlp结束后,wait启动,立即重新打开
      while(1)
      {
        wait(NULL);
        pid=fork();
        if(pid==0)
        {
          execlp("gedit","gedit","123.txt",NULL);
        }
      }
    }

  • 相关阅读:
    修复 Visual Studio Error “No exports were found that match the constraint”
    RabbitMQ Config
    Entity Framework Extended Library
    Navisworks API 简单二次开发 (自定义工具条)
    NavisWorks Api 简单使用与Gantt
    SQL SERVER 竖表变成横表
    SQL SERVER 多数据导入
    Devexpress GridControl.Export
    mongo DB for C#
    Devexress XPO xpPageSelector 使用
  • 原文地址:https://www.cnblogs.com/gd-luojialin/p/9215992.html
Copyright © 2011-2022 走看看