守护进程的相关概念

目录

一、进程组

二、作业

三、会话

控制终端:

前台进程组:

后台进程组:

四、守护进程

 1、定义

 2、 作用

3、创建守护进程的过程:


一、进程组

        在之前进程的概念中,有提到当一个可执行程序运行起来之后会形成一个进程。

        而实际上,当一个程序运行起来后形成的是一个进程组。进程组,顾名思义,就是一个或多个进程的集合。每个进程都有一个唯一的进程组ID。该进程组中的第一个运行起来的进程创建了该进程组,因此该进程为进程组的组长进程。而该进程的进程ID就是该进程组的组ID。

        进程组创建之后,只要进程组中还有一个进程存在,该进程组就存在,与组长进程是否存在无关。比如,当组长进程创建了一个进程组后,之后该进程组中有添加了许多进程,当组长进程退出后,只要还有一个进程存在,该进程就存在。

二、作业

        当一个进程运行起来形成一个进程组之后,该进程组是为了完成某一任务的,可以将该任务称为一项作业。可以说,一个进程组是与一项作业相对应的。所以说,shell在前后台控制的是一项作业或一个进程组而不是一个进程。一个进程组有多个进程组成,所以一项作业也由多个进程组成。

        shell可以运行一个前台作业及多个后台作业,这称为作业控制。作业与进程的区别在于,如果作业中的某个进程创建了子进程,该子进程属于该进程组,而不属于该作业。

当前台没有作业在运行时,shell在前台运行。当在前台运行一项作业后(包含进程1,2),shell被提到后台。此时,shell便不能接收其他用户输入的命令了。在前台作业运行过程中,进程1又创建了一个子进程3。此时该进程3与进程1,2同属一个进程组,但进程3不属于该前台作业。当进程1,2退出,但进程3还没退出时,表示前台作业执行结束,所以shell又被提到前台,可以接受用户输入的命令了。而进程3所在的进程组还存在,则它自动变为后台进程组,它所对应的作业被提到了后台继续运行。

注意:后台作业不能接收用户输入的命令即不能使用标准输入接收命令,但可以输出到屏幕上即可以使用标准输出或标准错误。

三、会话

        一个会话包括一个控制进程,一个前台作业和多个后台作业。当新打开一个终端,会创建一个会话。同时会有一个会话首进程(控制进程)将该会话与控制终端相连接。

控制终端:

        一个会话一般会拥有一个控制终端用于执行IO操作。会话的领头进程打开一个终端之后, 该终端就成为该会话的控制终端。与控制终端建立连接的会话领头进程也称为控制进程 (controlling process) 。一个会话只能有一个控制终端。

前台进程组:

        该进程组中的进程能够向终端设备进行读、写操作的进程组。例如登陆shell(例如bash)通过调用int tcsetpgrp(int fd, pid_t pgrp); 该函数为某个进程组pgrp关联终端设备fd,该函数执行成功后,该进程组pgrp成为前台进程组。

后台进程组:

        该进程组中的进程只能够向终端设备写。

四、守护进程

 1、定义

        守护进程是运行在后台的一种特殊进程,它独立于控制终端并且周期性地执行某种任务或循环等待处理某些事件的发生;它不需要用户输入就能运行而且提供某种服务,不是对整个系统就是对某个用户程序提供服务。Linux系统的大多数服务器就是通过守护进程实现的。        
        守护进程一般在系统启动时开始运行,除非强行终止,否则直到系统关机才随之一起停止运行;
        守护进程一般都以root用户权限运行,因为要使用某些特殊的端口(1-1024)或者资源;
        守护进程的父进程一般都是init进程,因为它真正的父进程在fork出守护进程后就直接退出了,所以守护进程都是孤儿进程,由init接管;
        守护进程是非交互式程序,没有控制终端,所以任何输出,无论是向标准输出设备stdout还是标准出错设备stderr的输出都需要特殊处理。
        守护进程的名称通常以d结尾,比如sshd、xinetd、crond等

 2、 作用


        1.守护进程是一个生存周期较长的进程,通常独立于控制终端并且周期性的执行某种任务或者等待处理某些待发生的事件
        2.大多数服务都是通过守护进程实现的
        3.关闭终端,相应的进程都会被关闭,而守护进程却能够突破这种限制


Linux系统的大多数服务器就是通过守护进程实现的。常见的守护进程包括:

系统日志进程syslogd、
web服务器httpd、
邮件服务器sendmail
数据库服务器mysqld等。


3、创建守护进程的过程:

1)fork()创建子进程,父进程exit()退出
这是创建守护进程的第一步。由于守护进程是脱离控制终端的,因此,完成第一步后就会在Shell终端里造成程序已经运行完毕的假象。之后的所有工作都在子进程中完成,而用户在Shell终端里则可以执行其他命令,从而在形式上做到了与控制终端的脱离,在后台工作。

2)在子进程中调用 setsid() 函数创建新的会话
在调用了fork()函数后,子进程全盘拷贝了父进程的会话期、进程组、控制终端等,虽然父进程退出了,但会话期、进程组、控制终端等并没有改变,因此,这还不是真正意义上的独立开来,而 setsid() 函数能够使进程完全独立出来。setsid()函数的作用。一个进程调用setsid()函数后,会发生如下事件:

• 首先内核会创建一个新的会话,并让该进程成为该会话的leader进程,
• 同时伴随该session的建立,一个新的进程组也会被创建,同时该进程成为该进程组的组长。
• 该进程此时还没有和任何控制终端关联。若需要则要另外调用tcsetpgrp,前面讲前台进程组时介绍过。

调用setsid()有以下3个作用:

• 让进程摆脱原会话的控制。
• 让进程摆脱原进程组的控制。
• 让进程摆脱原控制终端的控制。 

3)再次 fork() 一个孙进程并让子进程退出
为什么要再次fork呢:1、假定有这样一种情况,之前的父进程fork出子进程以后还有别的事情要做,在做事情的过程中因为某种原因阻塞了,而此时的子进程因为某些非正常原因要退出的话,就会形成僵尸进程,所以由子进程fork出一个孙进程以后立即退出,孙进程作为守护进程会被init接管,此时无论父进程想做什么都随它了。2、禁止重新打开控制终端:经过以上步骤,进程已经成为一个无终端的会话组长,但是它可以重新申请打开一个终端。为了避免这种情况发生,可以通过使进程不再是会话组长来实现,再一次通过fork创建新的子进程,使调用fork的进程退出。

4)在孙进程中调用 chdir() 函数,让根目录 ”/” 成为孙进程的工作目录

这一步也是必要的步骤,使用fork创建的子进程继承了父进程的当前工作目录。由于在进程运行中,当前目录所在的文件系统(如“/mnt/usb”)是不能卸载的,这对以后的使用会造成诸多的麻烦(比如系统由于某种原因要进入单用户模式)。因此,通常的做法是让"/"作为守护进程的当前工作目录,这样就可以避免上述的问题,当然,如有特殊需要,也可以把当前工作目录换成其他的路径,如/tmp,改变工作目录的常见函数是chdir。

5)在孙进程中调用 umask() 函数,设置进程的文件权限掩码为0
文件权限掩码是指屏蔽掉文件权限中的对应位。比如,有个文件权限掩码是050,它就屏蔽了文件组拥有者的可读与可执行权限。由于使用fork函数新建的子进程继承了父进程的文件权限掩码,这就给该子进程使用文件带来了诸多的麻烦。因此,把文件权限掩码设置为0,可以大大增强该守护进程的灵活性。设置文件权限掩码的函数是umask。在这里,通常的使用方法为umask(0)。

6)在孙进程中关闭任何不需要的文件描述符
同文件权限码一样,用fork函数新建的子进程会从父进程那里继承一些已经打开了的文件。这些被打开的文件可能永远不会被守护进程读写,但它们一样消耗系统资源,而且可能导致所在的文件系统无法卸下。

在上面的第2)步之后,守护进程已经与所属的控制终端失去了联系。因此从终端输入的字符不可能达到守护进程,守护进程中用常规方法(如printf)输出的字符也不可能在终端上显示出来。所以,文件描述符为0、1和2 的3个文件(常说的输入、输出和报错)已经失去了存在的价值,也应被关闭。

7)守护进程退出处理
当用户需要外部停止守护进程运行时,往往会使用 kill 命令停止该守护进程。所以,守护进程中需要编码来实现 kill 发出的signal信号处理,达到进程的正常退出。
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值