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\n",getpid());

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

  int state;
  pid_t pid=wait(&state);
  if(pid>0)
  {
    printf("Signal:%d,Exit:%d\n",state&0xff,(state>>8)&0xff);
  }
  //多个子进程,多个wait
  wait(NULL);
  printf("end fork :%d\n",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!\n");
      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\n",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\n",getpid());
    pid_t pidd=fork();
    if(pidd==0)
    {
    printf("this is a sub child :%d\n",getpid());
    //可以其他操纵
    //exec()...............
    //退出子子进程
    exit(0);
    }
    else
    {
      //退出子进程
      exit(0);
    }
  }
  else
  {
  //回收资源表,父进程退出
  wait(NULL);
  printf("this is a parent :%d\n",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);
    }
  }
}

猜你喜欢

转载自www.cnblogs.com/gd-luojialin/p/9215992.html