守护进程
守护进程的特点
- 后台服务进程
- 独立于控制终端
- 周期性执行某任务
- 不受用户登录注销影响
- 一般采用以d结尾的名字
进程组
进程组的组长
- 组里边的第一个进程就是该组的组长
- 进程组的ID等于组长的ID
会话(多个进程组)
创建一个会话的注意事项:
- 进程组长不能创建会话
- 创建会话的进程成为新进程组的组长
- 创建出的会话会丢弃原有的控制终端
获取进程所属的会话ID:
- pid_t getsid(pid_t pid);
创建一个会话:
- pid_t setsid(void);
创建守护进程的流程
- fork子进程,父进程退出
- 子进程创建新会话
- 改变当前目录到一个不可卸载目录
- 重设文件掩码(子进程会继承父进程掩码,重设掩码可以增加子进程的灵活性)
- 关闭文件描述符(由于守护进程和终端脱离,可以关闭0,1,2描述符释放资源)
- 执行核心工作
创建一个守护进程,每隔2s获取一次系统时间,将这个时间写入到磁盘文件中
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <stdio.h> #include <signal.h> #include <unistd.h> #include <sys/time.h> #include <time.h> #include <fcntl.h> void dowork(int no) { time_t curtime; //得到当前系统时间 time(&curtime); //格式化时间 char *pt = ctime(&curtime); //将时间写入文件 int fd = open("/home/badou/linux_learning/temp+++.txt", O_CREAT | O_WRONLY | O_APPEND, 0664); write(fd, pt, strlen(pt)+1); close(fd); } int main() { pid_t pid = fork(); if(pid > 0) { //父进程退出 exit(1); } else if(pid == 0) { //创建会话 setsid(); //改变进程的工作目录 chdir("/home/badou/linux_learning"); //重置文件掩码 umask(0); //关闭文件描述符 close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); //执行核心操作 //注册信号捕捉 struct sigaction act; act.sa_flags = 0; act.sa_handler = dowork; sigemptyset(&act.sa_mask); sigaction(SIGALRM, &act, NULL); //创建定时器 struct itimerval val; //第一次触发时间 val.it_value.tv_usec = 0; val.it_value.tv_sec = 2; //循环周期 val.it_interval.tv_usec = 0; val.it_interval.tv_sec = 1; setitimer(ITIMER_REAL, &val, NULL); while(1); } return 0; }