Intro
當我們編寫服務器代碼時,為了讓自己的服務器在意外崩潰時能夠及時的重啟,軟件看門狗就顯示出它的作用了,該看門狗進程是通過fork一個子進程(業務進程),父進程一旦捕獲到了子進程的結束信號就重新再fork一個子進程來實現的,下面將完整代碼貼上。
/************************************************
* 該例程講解Linux軟件看門狗的優雅編寫方法
*
* 編寫WatchDog有很多種方式:
* a.一個WatchDog.sh腳本程序
* b.一個WatchDog.exe可執行程序
* c.一個可執行程序里面包含WatchDog
*
* 本例程就是使用的c方式,通過父進程監控子進程的運行狀態來實現的
* 其中父進程就是子進程(具體的任務進程)的WatchDog
************************************************/
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
void childProcessFunc()
{
int i = 0;
while (true)
{
++i;
printf("i: %d, pid: %d, ppid: %d\n", i, getpid(), getppid());
if (i == 10)
{
// 子進程主動結束
//exit(0);
char* p = NULL;
*p = 1;
}
sleep(1);
}
}
void forkChildProcess(int)
{
int status = 0;
// 等待子進程中斷或終止,釋放子進程資源
// 否則死掉的子進程會變成僵屍進程
int pid = wait(&status);
if (pid < 0)
{
printf("error: %s\n", strerror(errno));
return;
}
// 如果子進程是由於某種信號退出的,捕獲該信號
if (WIFSIGNALED(status))
{
int signalNum = WTERMSIG(status);
printf("Child process was killed by signal num: %d\n", signalNum);
}
// 檢測是否生成了core文件
if (WCOREDUMP(status))
{
printf("Child process core dump file generated\n");
}
// 等待3秒鍾重新啟動子進程
sleep(3);
pid = fork();
if (pid == 0)
{
printf("Fork new child process\n");
childProcessFunc();
}
}
bool initWatchDog()
{
int pid = fork();
if (pid)
{
// 父進程一直監視子進程的運行狀態
while (true)
{
// 捕獲子進程結束信號
assert(signal(SIGCHLD, forkChildProcess) != SIG_ERR);
// 父進程掛起,當有信號來時被喚醒
pause();
}
}
else if (pid < 0)
{
return false;
}
return true;
}
int main()
{
printf("Main pid: %d\n", getpid());
// 初始化看門狗進程
bool ret = initWatchDog();
if (!ret)
{
printf("Init watch dog failed\n");
return 1;
}
printf("Init watch dog success...\n");
// 運行子進程代碼
childProcessFunc();
return 0;
}
該例子的github地址:https://github.com/chxuan/samples/blob/master/WatchDog/WatchDog.cpp