本文主要包括三个部分:
一是如何实现一个守护进程,二是如何检测一个进程是否活着,三是保证某一执行文件只有一个实例在运行。
1.守护进程
守护进程的最大特点就是脱离了中断,Linux提供了一个系统调用daemon(),要想自定义实现的话,主要包括以下六个步骤:
1.第一步是使用umask函数,把所有的文件屏蔽字置0。文件屏蔽字是可以继承的,当你有相关操作时,如果你要创建一个文件,继承过来的屏蔽字可能阻止你创建相关属性的文件。比如:如果你明确的创建一个文件为组可读,组可写。如果你没有把屏蔽字清零,那么继承过来的屏蔽字可能不允许你添加这两个属性。
2.第二步,创建一个子进程,并且令父进程退出。这样做有以下几个好处:一,如果守护进程是一个简单的shell命令启动的,那么父进程的终止可以使shell认为这个命令已经执行结束了。二,子进程继承了父进程的组ID,但又有自己的进程ID,所以我们可以保证目前的子进程不是进程组长。这一步也是我们接下来要用到的setid函数之前的必要条件。
3.使用setsid函数创建一个新的对会话。首先,该进程变为一个新的会话组的会话头。其次,成为了新的进程组的组长。最后该进程不再控制终端。在system V 下,一些人建议在此时重新fork一次,并且令父进程退出。第二个子进程仍然是一个守护进程。这样做可以保证当前进程不是一个会话组的组长,这样就可以防止他获得控制终端的能力。作为选择,为了防止获得终端的控制权,确定打开终端驱动时明确设置O_NOCTTY。
4.把当前工作目录变为根目录。当前的工作目录是继承父进程的。守护进程是一直存在的,除非你重启计算机。如果你的守护进程是挂载到文件系统上的,那这个文件系统就不能卸载掉。
5.不需要的文件描述符应当关掉。这样可以防止守护进程持有从父进程继承过来的文件描述符。我们可以获取最大的文件描述符,或者使用getrlimit函数来决定最大的文件描述符的值。并且全部关闭。(非必要)
6.一些守护进程把0,1,2这三个文件描述符指向/dev/null,这样的话,当库函数试图通过标准输入输出,标准错误时是没有效果的。当一个守护进程脱离了终端时,就没有地方打印信息;也没有地方接收来自用户的交互式输入。甚至当一个守护进程从一个交互式的会话开始,守护进程在后台运行,登陆会话关闭也不会影响到守护进程。如果其他用户用同样的终端登陆,我们不用设想从守护进程打印信息到终端,也别指望用户读取守护进程。
以上主要参考考:http://www.cnblogs.com/iceocean/articles/1650475.html
2.如何检查一个进程是否活着
判断一个进程是否活着,我们主要是通过kill这一系统调用来完成,先看一下kill的manual page:
<code class="hljs vhdl has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">#include <sys/types.h> #include <<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">signal</span>.h> int kill(pid_t pid, int sig) DESCRIPTION The kill() system call can be used <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">to</span> send any <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">signal</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">to</span> any <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">process</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">group</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">or</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">process</span>. <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">If</span> pid <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">is</span> <span class="hljs-typename" style="color: rgb(102, 0, 102); box-sizing: border-box;">positive</span>, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">then</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">signal</span> sig <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">is</span> sent <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">to</span> pid. <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">If</span> pid equals <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">then</span> sig <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">is</span> sent <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">to</span> every <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">process</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> the <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">process</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">group</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">of</span> the current <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">process</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">If</span> pid equals -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">then</span> sig <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">is</span> sent <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">to</span> every <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">process</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> which the call- ing <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">process</span> has permission <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">to</span> send signals, except <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">process</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span> (init), but see below. <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">If</span> pid <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">is</span> less than -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">then</span> sig <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">is</span> sent <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">to</span> every <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">process</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> the pro- cess <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">group</span> -pid. <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">If</span> sig <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">is</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">then</span> no <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">signal</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">is</span> sent, but error checking <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">is</span> still per- formed. <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> you can send a <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">signal</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">to</span> PID, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">and</span> returns <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> you can<span class="hljs-attribute" style="box-sizing: border-box;">'t</span> (don<span class="hljs-attribute" style="box-sizing: border-box;">'t</span> have <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">access</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">or</span> invalid PID)。 </code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; opacity: 0.665015; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li></ul>
所以kill(pid,0)可以用于检测一个为pid的进程是否还活着[在shell下面可以用ps来查找],基本逻辑如下:
<code class="hljs vbnet has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span>(kill(pid,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>)!=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) it<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">'s dead. </span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> it<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">'s alive. </span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; opacity: 0.665015; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>
3.保证某一执行文件只有一个实例在运行
这样的需求主要是解决保证只有同时只有一个这样的进程在运行,像MySQL都这样处理:
1.启动进程后,先检查pid文件是否存在,存在则读取之前写入的pid,然后用上面的kill(pid,0);来检查是否活着,
2.活着则退出进程,不允许再启动一个进程,否则启动并将当前的pid写入pid文件。写入的时候要锁住文件,避免
其他进程也往里面写,主要是lockf这个系统调用,方法是:
<code class="hljs cpp has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> writePidFile(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">char</span> *szPidFile) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/*open the file*/</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">char</span> str[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">32</span>]; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> lfp = open(szPidFile, O_WRONLY|O_CREAT|O_TRUNC, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0600</span>); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (lfp < <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">exit</span>(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/*F_LOCK(block&lock) F_TLOCK(try&lock) F_ULOCK(unlock) F_TEST(will not lock)*/</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (lockf(lfp, F_TLOCK, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) < <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) { <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">fprintf</span>(stderr, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Can't Open Pid File: %s"</span>, szPidFile); <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">exit</span>(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>); } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/*get the pid,and write it to the pid file.*/</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">sprintf</span>(str, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"%d\n"</span>, getpid()); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// \n is a symbol. </span> ssize_t len = <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">strlen</span>(str); ssize_t ret = write(lfp, str, len); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (ret != len ) { <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">fprintf</span>(stderr, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Can't Write Pid File: %s"</span>, szPidFile); <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">exit</span>(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>); } close(lfp); } </code>