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);
        }
      }
    }

  • 相关阅读:
    【UVa#10325】The Lottery
    【洛谷P1868】饥饿的奶牛
    【NOI2005】维护数列
    【NOIP2018】保卫王国
    【洛谷P4719】动态dp
    【NOI2014】魔法森林
    【洛谷P4234】最小差值生成树
    【国家集训队】Tree II
    面试1
    struts2中的方法的调用
  • 原文地址:https://www.cnblogs.com/gd-luojialin/p/9215992.html
Copyright © 2011-2022 走看看