上一篇我们讲了后台进程,本篇我们来讲讲守护进程。
有人会问,守护进程是什么样的进程呢?他和前面介绍的普通进程及后台进程又有什么区别呢?
其实守护进程和后台进程一样,也是不依赖于终端,父进程是操作,运行于后端的进程。它和后端进程的最大的特点是它具备捕获并处理信号的能力。
他是怎么做到这些的呢?
Linux系统中,提供了信号量处理函数,他们用于捕获运行过程中收到的信号并处理他们。而守护进程正是使用了这些函数的后台进程。
下面让我们来看看如何实现它
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
void catchSignal(int nSign)
{
void *array[10];
std::size_t size;
size = backtrace(array, 10);
int save_fd = dup(STDOUT_FILENO); //将标准输出重定向到文件
char bufBtFileName[512] = {0};
sprintf(bufBtFileName, "/tmp/%s.bt", GetProcessName());
int fd = open(bufBtFileName, (O_RDWR | O_CREAT), 0644);
dup2(fd,STDOUT_FILENO);
char **strings = backtrace_symbols(array, size);
for (int i = 0; i < size; i++)
printf( "%s\n", strings[i]);
free(strings);
char cmd[64] = "addr2line -C -f -e ";
char* prog = cmd + strlen(cmd);
readlink("/proc/self/exe", prog, sizeof(cmd) - strlen(cmd) - 1);// 获取进程的完整路径
FILE* fp = popen(cmd, "w");
if (fp != NULL)
{
for (int i = 0; i < size; ++i)
{
fprintf(fp, "%p\n", array[i]);
}
pclose(fp);
}
exit(0);
}
void setProcSignal()
{
signal( SIGINT, SIG_IGN);
signal( SIGHUP, SIG_IGN);
signal( SIGQUIT, SIG_IGN);
signal( SIGPIPE, SIG_IGN);
signal( SIGTTOU, SIG_IGN);
signal( SIGTTIN, SIG_IGN);
signal( SIGCHLD, SIG_IGN);
signal( SIGTERM, SIG_IGN);
signal( SIGHUP, SIG_IGN);
struct sigaction sig;
sig.sa_handler = catchSignal;
sigemptyset(&sig.sa_mask);
sig.sa_flags = SA_RESTART | SA_SIGINFO;
sigaction(SIGSEGV, &sig, NULL); // 无效内存引用
sigaction(SIGABRT, &sig, NULL); // 异常终止
}
void deamon_init()
{
pid_t pid;
if ((pid = fork()) != 0) exit(0);
setsid();
if ((pid = fork()) != 0) exit(0);
rlimit rlim;
if (getrlimit(RLIMIT_NOFILE, &rlim) == 0)
{
for (int fd = 3; fd <= (int)rlim.rlim_cur; fd++)
{
close(fd);
}
}
umask(0);
setpgrp();
int fd = -1;
if ((fd = open("/dev/null", O_RDWR)) == -1) exit(1);
dup2(fd, STDIN_FILENO);
dup2(fd, STDERR_FILENO);
close(fd);
return 0;
}
int main()
{
deamon_init();
setProcSignal();
return 0;
}