Skip to content

Instantly share code, notes, and snippets.

@zhaoyao
Last active April 2, 2021 16:18
Show Gist options
  • Save zhaoyao/3159167 to your computer and use it in GitHub Desktop.
Save zhaoyao/3159167 to your computer and use it in GitHub Desktop.
double fork trick

避免僵尸进程出现.

如果fork后不进行waitwaitpid,那么子进程将会成会僵尸进程。double fork后, second child成为孤儿进程,由init负责后续的清理工作。

#include <stdio.h>
#include <unistd.h> 
#include <stdlib.h>
#include <sys/wait.h>

int main(void) {
  pid_t pid; 
  
  if ( (pid = fork()) < 0) { 
    printf("fork error\n"); exit(1);

  } else if (pid == 0) { 
    // first child
    if ( (pid = fork()) < 0) { 
      printf("fork error\n"); exit(1);

    } else if (pid > 0) { 
      // exit first child
      exit(0);
    }    

    //等待first child exit,使得下面能够正确得到ppid == init
    sleep(2);
    printf("second child, ppid = %d\n", getppid());
    exit(0);
  }

  // 清理first child,保证first child不会成为僵尸进程
  if (waitpid(pid, NULL, 0) != pid) {
    printf("waitpid error\n"); exit(1); 
  }

  exit(0);
}

避免守护进程获取到控制终端

在第一次fork后进行setsid, 让first child成为session leader并与控制终端脱离,这样second child就无法再获得控制终端了(非session leader)。

#include <stdio.h>
#include <unistd.h> 
#include <stdlib.h>
#include <sys/wait.h>

void has_tty()
{
  int tty = open("/dev/tty", O_RDWR);
  if (tty > 0) { 
    printf("process %d has tty %d\n", getpid(), tty); 
  } else {
    printf("process %d has no tty\n", getpid()); 
  }
}


int main(void) {
  pid_t pid; 

  if ( (pid = fork()) < 0) { 
    printf("fork error\n"); exit(1);

  } else if (pid == 0) { 
    // first child
    has_tty(); //拥有tty
    setsid();
    has_tty(); //已经断开tty

    if ( (pid = fork()) < 0) { 
      printf("fork error\n"); exit(1);

    } else if (pid > 0) { 
      // exit first child
      exit(0);
    }    

    has_tty(); //已经断开tty
    sleep(2);
    printf("second child, ppid = %d\n", getppid());
    exit(0);
  }

  // 清理first child,保证first child不会成为僵尸进程
  if (waitpid(pid, NULL, 0) != pid) {
    printf("waitpid error\n"); exit(1); 
  }

  exit(0);
}

参考:

  • apue 第八章:进程控制
  • stackoverflow [how-do-you-create-a-daemon-in-python] 1
  • [fluentd: supervisor.rb] 2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment