Linux下后台进程与守护进程的区别
时间:2019-05-05 13:00 来源:linux.it.net.cn 作者:IT
一、后台进程与守护进程
1、守护进程已经完全脱离终端控制台了,而后台程序并未完全脱离终端(在终端未关闭前还是会往终端输出结果);
2、守护进程在关闭终端控制台时不会受影响,而后台程序会随用户退出而停止,需要在以nohup command &格式运行才能避免影响;
3、守护进程的会话组和当前目录,文件描述符都是独立的。后台运行只是终端进行了一次fork,让程序在后台执行,这些都没改变;
二、守护进程的特点
守护进程(Daemon)是在后台运行的一种特殊进程,它脱离于终端,从而这可避免进程被任何终端所产生的信号打断,它在执行进程中的产生信息也不在任何终端上显示。守护进程周期性地执行某种任务或等待处理某些发生的事件,Linux的大多数服务器就是用守护进程实现的。
三、守护进程编程要点
1、屏蔽一些有关控制终端操作的信号,是为了防止在守护进程没有正常启动起来前,控制终端受到干扰退出或挂起。代码如下:
/*处理可能的终端信号 */
signal(SIGTTOU, SIG_IGN);
signal(SIGTTIN, SIG_IGN);
signal(SIGTSTP, SIG_IGN);
signal(SIGHUP , SIG_IGN);
2、在后台运行
/*是父进程,结束父进程,子进程继续 */
if(fork)
exit(0);
3、脱离控制终端和进程组:
(1)一个进程属于一个进程组,进程组号(PGID)就是进程组长的进程号(PID)
(2)同进程组中的进程共享一个控制终端,这个控制终端默认是创建进程的终端
(3)一个进程关联的控制终端和进程组通常是从父进程继承下来的,因此,这个子进程仍然受到父亲进程终端的影响,因为终端产生的信号会发送给前台进程组的所有进程。
基于以上原因,需要让为个子进程彻底摆脱该终端的影响,需要调用setsid使子进程成为新的会话组长,代码如下:
setsid;
setsid调用成功后,调用此函数的进程成为新的会话组长和新的进程组长,并与原来的进程组脱离关系。由于会话过程对控制终端的独占性,进程同时与控制终端脱离。
4、禁止进程重新打开控制终端,采用的办法是再次创建一个子进程,并让父亲进程退出,该子进程不再是会话组长,从而达到目的。代码如下:
/*结束第一子进程,第二子进程继续 */
if(fork)
exit(0);
5、关闭打开的文件描述符。因为进程从创建它的父进程那里继承了打开的文件描述符,一般情况下不再需要。如不关闭,将会浪费系统资源。代码如下:
#define NOFILE 256
for(i=0; i
close(i);
6、改变当前工作目录。进程活动时,其工作目录所在的文件系统不能卸载。因此需要将守护进程的工作目录改变到合适的目录。代码如下:
chdir("/tmp");
7、重设文件创建掩码。进程从创建它的父进程那里继承了文件创建掩码。它可能修改守护进程所创建的文件的存取权限。代码如下:
umask(0);
8、处理SIGCHLD信号(子进程退出信号)。如果不等待子进程结束,子进程将成为僵尸进程从而占用系统内核资源。
/*将子进程退出信号设为SIG_IGN,让系统帮助回收进程资源 */
signal(SIGCHLD, SIG_IGN);
整体代码如下:
#define NOFILE 256
void DaemonMode
{
int num = 0;
int fd0, fd1, fd2;
/*屏蔽可能的信号 */
signal(SIGTTOU, SIG_IGN);
signal(SIGTTIN, SIG_IGN);
signal(SIGTSTP, SIG_IGN);
signal(SIGHUP , SIG_IGN);
if(fork)
exit(0);
setsid;
if(fork)
exit(0);
chdir("/tmp/httpd");
umask(0);
for(; num
close(num);
/*将输入、输出重定向。因为之前描述符都关闭了,所以新打开值为0、1、2 */
fd0 = open("/dev/null", O_RDWR);
fd1 = dup(0);
fd2 = dup(0);
signal(SIGCHLD, SIG_IGN);
}
补充 setsid函数功能:
如果调用进程已经是一个进程组的组长,则此函数返回错误。为了杜绝这种情况,通常先调用fork创建子进程,然后使其父进程终止,而子进程继续,在子进程中调用此函数。如果调用此函数的进程不是一个进程组组长,则此函数会创建一个新会话,调用setsid函数的进程成为新的会话的领头进程,
并与其父进程的会话组和进程组脱离。由于会话对控制终端的独占性,进程同时与控制终端脱离。
(责任编辑:IT)
一、后台进程与守护进程 1、守护进程已经完全脱离终端控制台了,而后台程序并未完全脱离终端(在终端未关闭前还是会往终端输出结果); 2、守护进程在关闭终端控制台时不会受影响,而后台程序会随用户退出而停止,需要在以nohup command &格式运行才能避免影响; 3、守护进程的会话组和当前目录,文件描述符都是独立的。后台运行只是终端进行了一次fork,让程序在后台执行,这些都没改变; 二、守护进程的特点 守护进程(Daemon)是在后台运行的一种特殊进程,它脱离于终端,从而这可避免进程被任何终端所产生的信号打断,它在执行进程中的产生信息也不在任何终端上显示。守护进程周期性地执行某种任务或等待处理某些发生的事件,Linux的大多数服务器就是用守护进程实现的。 三、守护进程编程要点 1、屏蔽一些有关控制终端操作的信号,是为了防止在守护进程没有正常启动起来前,控制终端受到干扰退出或挂起。代码如下: /*处理可能的终端信号 */ signal(SIGTTOU, SIG_IGN); signal(SIGTTIN, SIG_IGN); signal(SIGTSTP, SIG_IGN); signal(SIGHUP , SIG_IGN); 2、在后台运行 /*是父进程,结束父进程,子进程继续 */ if(fork) exit(0); 3、脱离控制终端和进程组: (1)一个进程属于一个进程组,进程组号(PGID)就是进程组长的进程号(PID) (2)同进程组中的进程共享一个控制终端,这个控制终端默认是创建进程的终端 (3)一个进程关联的控制终端和进程组通常是从父进程继承下来的,因此,这个子进程仍然受到父亲进程终端的影响,因为终端产生的信号会发送给前台进程组的所有进程。 基于以上原因,需要让为个子进程彻底摆脱该终端的影响,需要调用setsid使子进程成为新的会话组长,代码如下: setsid; setsid调用成功后,调用此函数的进程成为新的会话组长和新的进程组长,并与原来的进程组脱离关系。由于会话过程对控制终端的独占性,进程同时与控制终端脱离。 4、禁止进程重新打开控制终端,采用的办法是再次创建一个子进程,并让父亲进程退出,该子进程不再是会话组长,从而达到目的。代码如下: /*结束第一子进程,第二子进程继续 */ if(fork) exit(0); 5、关闭打开的文件描述符。因为进程从创建它的父进程那里继承了打开的文件描述符,一般情况下不再需要。如不关闭,将会浪费系统资源。代码如下: #define NOFILE 256 for(i=0; i close(i); 6、改变当前工作目录。进程活动时,其工作目录所在的文件系统不能卸载。因此需要将守护进程的工作目录改变到合适的目录。代码如下: chdir("/tmp"); 7、重设文件创建掩码。进程从创建它的父进程那里继承了文件创建掩码。它可能修改守护进程所创建的文件的存取权限。代码如下: umask(0); 8、处理SIGCHLD信号(子进程退出信号)。如果不等待子进程结束,子进程将成为僵尸进程从而占用系统内核资源。 /*将子进程退出信号设为SIG_IGN,让系统帮助回收进程资源 */ signal(SIGCHLD, SIG_IGN); 整体代码如下: #define NOFILE 256 void DaemonMode { int num = 0; int fd0, fd1, fd2; /*屏蔽可能的信号 */ signal(SIGTTOU, SIG_IGN); signal(SIGTTIN, SIG_IGN); signal(SIGTSTP, SIG_IGN); signal(SIGHUP , SIG_IGN); if(fork) exit(0); setsid; if(fork) exit(0); chdir("/tmp/httpd"); umask(0); for(; num close(num); /*将输入、输出重定向。因为之前描述符都关闭了,所以新打开值为0、1、2 */ fd0 = open("/dev/null", O_RDWR); fd1 = dup(0); fd2 = dup(0); signal(SIGCHLD, SIG_IGN); } 补充 setsid函数功能: 如果调用进程已经是一个进程组的组长,则此函数返回错误。为了杜绝这种情况,通常先调用fork创建子进程,然后使其父进程终止,而子进程继续,在子进程中调用此函数。如果调用此函数的进程不是一个进程组组长,则此函数会创建一个新会话,调用setsid函数的进程成为新的会话的领头进程, 并与其父进程的会话组和进程组脱离。由于会话对控制终端的独占性,进程同时与控制终端脱离。 (责任编辑:IT) |