- 一、守护进程是什么?
- 二、创建守护进程的过程
- 1.枯燥的概念
- 2.直观的代码
- 总结
一、守护进程是什么?
定义:脱离于终后台服务程序端,在后台独立运行的程序;
特点:
- 独立控制终端,用户不需要和终端交互;
- 周期性的执行某任务;
- 不受用户登录注销的影响;
- 一般采用d结尾的名字(服务)
了解了守护进程的基本概念之后,还需要了解两个知识点:进程组和会话
- 进程组
一个或多个进程的集合;
进程组ID作为唯一标识;
组长进程是进程组的第一个进程;
进程组的ID == 进程组的组长的ID; - 会话
会话是由多个进程组组成; - 创建一个会话注意的事项
*不能是组长进程;
创建会话的进程成为新进程组的组长;
创建的新会话会丢弃原有的控制终端;
一般步骤:先fork(),父进程死,子进程创建会话(setsid());
获取进程所属的会话ID
pid_t setsid(pid_t pid);
创建一个会话:
pid_t setsid(void);
- 创建子进程,父进程退出;
- 子进程创建新的会话,调用setsid();
setsid()函数的作用
- 在上一步,调用fork()创建子进程,再将父进程退出;
- 而在调用fork()时,子进程全盘拷贝了父进程的会话、进程组和控制终端,虽然父进程退出了,但是这些没有改变,因此还不是真正意义的独立开来;
- 而setsid()可以使进程完全独立,从而摆脱其它进程的控制。
-
改变当前目录为根目录
-
重设文件权限掩码
文件权限掩码是指屏蔽文件权限的对应位;
比如,有一个文件的权限掩码是050,它就屏蔽了文件组的可读和可执行权限。
使用fork()新建的子进程继承了父进程的文件权限掩码,这会给子进程使用文件带来很多麻烦,因此把文件权限掩码设置为0 ,可以增强守护进程的灵活性,一般用umask(0);
- 关闭文件描述符
与文件权限码一样,使用fork()创建的子进程会继承父进程的一些已经打开的文件,这些文件可能用于不会被守护进程读写,但是它们一直消耗系统资源。
2.直观的代码在第2步之后,子进程即守护进程已经与所属终端断了联系;
因此,从终端输入的字符不可能到达守护进程,守护进程中用常规方法输出的字符也不可能在终端打印出来;
所以,文件描述符0(输入),1(输出),2(报错)已经失去了存在的价值,应该被关闭。
代码如下:
#include#include #include #include #include #include #include #include #include void func(int no); // callback function int main(int argc, char **argv) { pid_t pid = fork(); if(pid >0) { printf("parent process exitn"); _exit(1); } else if(pid == 0) { setsid(); //child create session umask(0); close(STDIN_FILENO); //close file descriptor close(STDOUT_FILENO); close(STDERR_FILENO); struct sigaction act; act.sa_flags = 0; act.sa_handler = func; sigaddset(&act.sa_mask, SIGQUIT); itimerval time; //set timer time.it_value.tv_sec = 2; time.it_value.tv_usec = 0; time.it_interval.tv_sec = 1; time.it_interval.tv_usec = 0; sigaction(SIGVTALRM, &act, NULL); setitimer(ITIMER_VIRTUAL, &time, NULL); while(true); } return 0; } void func(int no) { time_t currtime; time(&currtime); char* ptr = ctime(&currtime); int fd = open("/home/fork/setsid.txt", O_CREAT | O_WRONLY | O_APPEND, 0777); write(fd, ptr, sizeof(ptr)+1); close(fd); }
总结
这部分知识点有点枯燥啊,守护进程,孤儿进程,僵尸进程,继续努力,稍后再更新!



