posix的特性——fork

记得之前曾经在一段Python中介绍过python的mulitprocess模块在windows的不兼容。其中提及了linux/Unix特有的fork方式,而windows无法实现导致的死循环。当时只是提到了一下,重点不同的关系,没有深究。

fork,顾名思义就是一把叉子,或者专业一点叫做复制叉。作为sys/type.h的一个函数,系统在每次调用fork()之后,将会以此为分叉,对进程本身进行复制,新的进程和旧进程有近乎完全一致的cpu时间和内存寄存器。

fork模型

这本身并不重要,重要的是对于fork()函数的返回而言,父进程返回的是子进程的pid,而子进程返回的是0,当然还有一个-1的返回表示fork()的失败。对与C大致如此:

#include <unistd.h>;
#include <sys/types.h>;

main ()
{
        pid_t pid;
        pid=fork();

        if (pid < 0)
                printf("error in fork!");
        else
        {
			if (pid == 0)
                        {
                                 printf("i am the child process, my process id is %d\n",getpid());
		                 exit();
                        }
			else
                        {
                                printf("i am the parent process, my process id is %d\n",getpid());
				exit();
                         }
         }
}

执行后,父进程和子进程分别将自己的Pid打印出来。

既然如此,对于我常用的php来说,可以同样做到后端执刑一些耗时的操作,从而达到异步的效果:

function mulitProcess()/*{{{*/
{
        if (function_exists(pcntl_fork))
        {
            $pid = pcntl_fork();

		    if ( $pid === -1 )
		    {
		    	return false;
		    }
		    elseif ( $pid )
		    {
                        usleep(10);
                        exit();
                    }
                    else
                    {
                         doBackground();
                    }
        }
        // windows system or php not support PCNTL libs
        else
        {
			doBackground();
        }
}

对于很多守护进程来说,脱离shell(即“脱壳”)正是利用了这种方式进行进程复制。对与PHP来说需要进行2次fork之后配合一个死循环即可,当然为了防止死循环真的“死掉”需要sleep()函数来进行休眠:

function daemonize() /*{{{*/
{
    $pid    =   pcntl_fork();

    if (-1 == $pid)
    {
        return false;
    }
    elseif ($pid)  //parent process
    {
        usleep(500);
        exit();
    }
    $sid    =   posix_setsid();

    if (!$sid)
    {
        return false;
    }

    $pid    =   pcntl_fork();

    if ( -1 == $pid )
    {
        return false;
    }
    elseif ($pid)
    {
        usleep(500);
        exit(0);
    }

    // deny process display and io
    if (defined('STDIN'))
            fclose(STDIN);

    if (defined('STDOUT'))
            fclose(STDOUT);

    if (defined('STDERR'))
            fclose(STDERR);
    while(true)
            doSomeThing();

}/*}}}*/

需要注意的是,windows没有fork(),php直接屏蔽了PCNL函数库,而python相对没有一棒子打死。Python采用的方式等于在命令行重新调用一次脚本,如果直接将没有考虑到这个问题的python脚本直接移植windows的话进程数量将会爆炸式增长,很快就会导致资源耗尽。由于我在windows上大多只是进行测试而已,多进程带来的性能优势不重要,习惯上我的方法就是使用threading模块替换掉mulitprocessing模块。写个示例:

try: #if os.name == 'posix':
    from multiprocessing import Process, Queue
except: #else:
    from threading import Thread as Process
    from Queue import Queue

windows模拟fork模型

推荐阅读:
从sysV的init说起

首先是庆祝我们开源小站再次搬家 Read more

古董命令nice/renice

一开始学习Linux时,曾经有 Read more

ctime/atime/mtime的区别

我个人觉得这并不是一个很困扰人 Read more

搭建Openstack集群

算起来Litrin在生产环境中 Read more

发表评论

电子邮件地址不会被公开。 必填项已用*标注

请补全下列算式: *

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据