浅显理解*nix下的医护进程机制及fork函数

发布时间:2018-10-23  栏目:w88优德官网电脑版  评论:0 Comments

新近闲暇时更仔细看了瞬间memcached的使验证文档,硬在头皮看了几许源码,有时候看到部分涩的c函数感觉实在恍惚只能过了。不过为未算是是均无收获,终于LZ还敢于再次看c语言,终于LZ又看起了c语言,终于近期之睡觉质量一目了然好了广大。扯淡到此结束,下面记录转温馨的学习心得。

一、Unix Daemon Process

memcached的守护进程机制下藏的Unix daemon模式(daemon.c),它的落实部分源码如下:

图片 1图片 2

memcached daemon.c
#if defined __SUNPRO_C || defined __DECC || defined __HP_cc
# pragma ident "@(#)$Header: /cvsroot/wikipedia/willow/src/bin/willow/daemon.c,v 1.1 2005/05/02 19:15:21 kateturner Exp $"
# pragma ident "$NetBSD: daemon.c,v 1.9 2003/08/07 16:42:46 agc Exp $"
#endif

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include "memcached.h"

int daemonize(int nochdir, int noclose)
{
    int fd;

    switch (fork()) { /*fork一个子进程*/
    case -1:
        return (-1);
    case 0:
        break;
    default:
        _exit(EXIT_SUCCESS);/*终结父进程*/
    }

    if (setsid() == -1)/*创建新的session(setsid),使当前进程成为该session的头进程*/
        return (-1);

    if (nochdir == 0) {
        if(chdir("/") != 0) {/*改变工作目录到“/”根目录*/ 
            perror("chdir");
            return (-1);
        }
    }

    if (noclose == 0 && (fd = open("/dev/null", O_RDWR, 0)) != -1) {/*重定向标准输入输出到/dev/null*/
        if(dup2(fd, STDIN_FILENO) < 0) {/*复制STDIN_FILENO、STDOUT_FILENO和STDERR_FILENO的描述符到fd*/
            perror("dup2 stdin");
            return (-1);
        }
        if(dup2(fd, STDOUT_FILENO) < 0) {
            perror("dup2 stdout");
            return (-1);
        }
        if(dup2(fd, STDERR_FILENO) < 0) {
            perror("dup2 stderr");
            return (-1);
        }

        if (fd > STDERR_FILENO) {
            if(close(fd) < 0) {
                perror("close");
                return (-1);
            }
        }
    }
    return (0);

实际工作流程处理如下:

图片 3

在押源码和拍卖流程图感觉好像也是寻常。学校里老师提操作系统,必然关系我们所熟知的才用户就任务操作系统PC
DOS(Disk Operating
System), 单用户仅任务操作系统是指同一尊微机以只能有一个用户以利用,该用户同样不行只能交给一个功课,一个用户独自享受系统的漫天硬件及软件资源。和DOS截然不同之是…哎,说来谈长,Unix在二十世纪七十年代就说明了fork函数,真正落实多任务之操作系统,这样Unix系统可以多人数大多任务地并行处理。所以站于操作系统发展之历史角度,每个看上去分外粗略的逻辑都是甚牛之跨越,还是认为十分微妙,这里来必不可少抄一段daemon的概念来让协调答应一下。

1、什么是Daemon Process(守护进程)
Daemon(守护进程)是运作于后台的如出一辙种植异常进程。它独自为决定终端以周期性地执行某种任务还是等处理某些发生的波。它不待用户输入就可知运作而提供某种服务,不是针对性全体系即是指向有用户程序提供劳动。*nix系统的多数服务器就经过守护进程实现的。常见的医护进程包括系统日志进程syslogd、
web服务器httpd、邮件服务器sendmail和数据库服务器mysqld等(看到此会无会见起“这tmd不就是是windows服务”的错觉?)。守护进程一般以系统启动时开始运行,除非强行终止,否则直到系统关机都维持运行。守护进程时以最佳用户(root)权限运行,因为其而采取异乎寻常之端口(1-1024)或看一些特殊的资源。一个护理进程的父进程是init进程,因为她确实的父进程在fork出子进程后就是早子进程exit退出了,所以它们是一个由于init继承的孤儿进程。守护进程是免交互式程序,没有控制终端,所以任何输出,无论是向专业输出设备stdout还是正式出错设备stderr的输出都要新鲜处理。

2、工作原理
*nix守护进程的做事模式是服务器/客户机(Server/Client),服务器在一个一定的端口上监听(Listen)等待客户连接,连接成功后服务器和客户端通过端口进行数量通信。守护进程的工作就是是开拓一个端口,并且监听(Listen)等待客户连接。如果客户端起一个连要,守护进程就创造(fork)一个子服务器响应此连续,而主服务器继续监听其他的劳务要。

在押了点的有数接触阐述与认证,熟悉windows的朋友肯定会联想到windows服务。虽然windows下子进程的概念充分少有人提,但其呢真的是有的,至于windows内部是休是透过fork实现子进程的,只能恕我孤陋寡闻了。

 

二、fork函数

由memcached的处理流程及得望实现守护进程机制的率先步是先fork一个子进程。看了田园里T2写的一样首稿子说fork的一律志编程书,印象挺深刻。下面可以关押一个传开的双重简单直接的讲课fork函数的例子:

图片 4图片 5

aboutfork#include <unistd.h>;

#include <sys/types.h>;



main ()

{

        pid_t pid;  //fork函数返回值

        pid=fork(); //通过fork函数给进程id赋值



        if (pid < 0)

                printf("error in fork!");

        else if (pid == 0)

                printf("i am the child process, my process id is %d\n",getpid());

        else

                printf("i am the parent process, my process id is %d\n",getpid());

 

斯函数最牛之地方是,表面上其的法判断只能有一个也真(即只能打印(printf)一糟),实际的出口为非熟识*nix的寻常开发人员如区区在产感到老不解,在linux下运行,它的莫过于出口为:

i am the child process, my process id is 3279
i am the parent process, my process id is 3278

面的出口可能于不同的linux内核(kernel)实现上输出顺序也未一致,但是连输出两履。开始笔者一下子为是想得到为什么两执都打印出,因为起常规程序运行角度理解,一个历程顺序执行,不管pid是不怎么,都当只打印一实行才对,可是fork(分叉)函数却足以打破我们这种思想一贯。下面摘抄一段子fork函数及子进程工作规律:

由于fork
创建的初过程被称为子进程(该过程几乎是现阶段历程的一个了拷贝),
fork
函数被调用一不善,但是回到两糟糕。两糟糕回到的绝无仅有区别是分段进程的返回值是0,而大进程的回值则是新子进程的ID。将子进程的ID
返回给爸爸进程的说辞是:一个过程可以来差不多只支行进程,并且没有拖欠过程几乎是现阶段历程的一个全拷贝函数是一个过程取得其子进程的过程ID。fork
在子进程面临归回0的理由是:一个历程只能有一个父进程,并且可透过getppid
函数获得其父亲进程的ID。子进程同父进程继续执行fork
调用后的吩咐,子进程是大人进程的副本。例如:子进程而取得父亲进程的数空间、堆和库房的副本。

地方就段话看上去好像比较深,实际上,如果我们学习过操作系统和c语言,应该力所能及读懂她的大概意思,当然这里要要正确理解父进程和子进程也就是是过程的定义。

这就是说什么是经过也?

我们或许已看到了无数面试题和参考书在议论什么是经过同线程以及二者之间的干。这里为无克免俗,顺带提一下历程的概念深化大家的明亮:一个过程在内存里产生三有些数据,即”代码段”、”堆栈段”和”数据段”,这三个组成部分是成一个一体化的可实施单元的画龙点睛之成。”代码段”就是存了程序代码的多寡,假如机器中生频繁个过程运行相同的一个次,那么她就可以使相同的代码段。”堆栈段”存放的就是子程序的回到地址、子程序的参数和程序的有的变量。而数据段则存放程序的全局变量,常数以及动态数据分配的多寡空间(如用malloc之类的函数取得的上空)。
乘势开发语言的前进,现在发生成百上千的下还是经过发出比较完善的内存管理机制(比如.NET的托管环境(CLR)、Java虚拟机等)的尖端语言开发之,所以便开发者平时对内存分配和保管几乎不用怎么费心,所以小底层基本的事物理解的为无是挺理解。但是事实上高级语言最终要得要透过类似IL(MS中间语言)或者第二进制字节码(bytecode)“翻译”成原生代码(native
code)通过CPU执行,所以本质上我们通过高档语言编写的程序执行时还是急需在内存里维护”代码段”、”堆栈段”和”数据段”这三组成部分。

哪个就要说了,既然经过要内存维护这三局部,创建子进程不就需要差不多分配内存多维护数据了为?fork的体系开发不见面充分可怜也?哈哈,这个也多亏自己的疑问,这里由于自己很勿熟识*nix,虽然道听途说看了一些诠释,但是自我感觉理解的还不是最透彻,这里就临时保留自己之观,希望有胸的公能查阅一些资料深入学习一下。

 

脚来看点看上去及其简单的按传说可以便捷为死操作系统的c函数:

   void main() 
   { 
     for( ; ; ) fork(); 
   } 

系是怎为作死的为?据说原理就是是其一次什么吗无开,就是死循环地fork,让程序不断出过程,而这些经过又不断发生新的进程…其结果是系出了成百上千底经过,直到资源不足而夭折。

实质上是死循环在我看来还免是无限牛之。分析者的代码,for循环一糟闹一个子过程,循环两赖有两只子进程…其实进程个数还是依照代表数级数增长。想象一下假如起个函数执行同样不良,然后能够让过程产生子进程,子进程有孙子进程……如此递归执行,进程仍指数层面膨胀,这个难道就是是传说被的fork炸弹吗(这个函数应该怎么编写呢?网上看到一个,很简单,欢迎您的解答)?

一体化感觉fork的运行机制还是生有意思的。实际上现在极其被自家道谢兴趣之是基本上进程中如何如多线程编程一样实现数量共享和一起。不管是大半进程或多线程,数据共享以及合(通信)一直是个子等难题,有日得抽空再美收拾总结一下。

 

参考:

http://www.cnblogs.com/leoo2sk/archive/2009/12/11/talk-about-fork-in-linux.html

http://pubs.opengroup.org/onlinepubs/009695399/functions/fork.html

http://www.berlinix.com/unix_daemon.html

http://www.phpx.com/happy/thread-131124-1-1.html

http://kb.cnblogs.com/page/48194/

http://code.google.com/p/memcached/wiki/NewCommands

留下评论