C语言程序下后台执行系统命令


 在代理进程适配代码上做开发时,业务场景下注册了回调函数。回调函数功能就是执行一些列后台命令,最初使用的system()函数,耗时较长,同时发现执行后,当前进程会崩溃。至于system函数为什么会崩溃,网上有少量的相同情况描述(如 http://bbs.csdn.net/topics/350031745 描述可能是glibc组件版本问题,但目前已经是高版本),据了解也有回调超时,强制复位进程之说。针对system()函数本身的问题,也尝试过http://blog.sina.com.cn/s/blog_8043547601017qk0.html 推荐的基于管道的popen和pclose函数,但问题仍然存在,因此这里认为是回调函数超时导致。

 

如果是超时机制,那么命令就不能执行耗时太久。根据业务场景分析,实际上也不需要命令的返回结果,也就是无需等待系统命令执行完再返回,完全可以后台执行。

 

首先,研究system()函数的原理,实际上是3步:

(1)执行使用fork()复制一个子进程

(2)在子进程中执行exec族函数调用系统命令

(3)子进程执行过程中父进程等待子进程执行完然后回收子进程资源,这里父进程会阻塞到子进程结束。

可以通过ps -ef看到system函数的确是创建子进程来执行系统命令。显然这里不执行第三步,就可以起到后台执行的作用。但是单纯的去掉第三步这种方式虽然能够达到目的,但是父进程不调用wait或waitpid,并且父进程不结束,那么子进程执行完后会变成僵尸进程,占用系统进程资源。因此单纯这样处理是不行的。

 

避免僵尸进程,网上提供了多种处理方式,包括:

a.父进程通过wait和waitpid等函数等待子进程结束。单纯的等待如同system函数,会导致父进程挂起,显然不可行。

b.执行的命令后添加后添加&,后台执行。这样就将后台执行责任交给了调用者,一是无法限制后续开发必须加上&以免进程崩溃问题再现,二是参数可以是多个系统命令,这种情况下需要每条命令都追加&,并且这样还会导致多条命令之间的时序也无法控制。

c.不处理SIGCHLD信号,调用signal(SIGCHLD,SIG_IGN); 忽略 SIGCHLD信号,可以理解为告诉系统我对子进程的结束不感兴趣,系统自己回收就可以了。 这种方式实测是可行的,但是该调用效果需要持续到子进程结束,即这是一种进程状态,相当于修改了进程属性,可能影响进程其他功能,考虑到对其本质的理解还不够透彻,没有采用这种方法。

d. 先创建一个子进程,子进程再创建孙进程,命令由孙进程处理,子进程直接返回,父进程回收子进程。这样子进程实际上是不会阻塞的,父进程也能够及时回收子进程而几乎没有阻塞。而子进程结束后,孙进程由init接管,孙进程结束后自动由系统回收,不会变为僵尸进程。

 

最终选择的方案是d方案,兼顾了a、b、c方案的不足点,应该可以说是比较稳妥的方法了。另外这里选用的vfork函数,而不是fork函数,由于子孙进程只用于执行exec命令,相比fork函数减少了不必要的复制父进程信息的步骤。注意vfork执行成功则在调用进程返回生成的进程的pid,失败则返回负数,而在生成的进程中返回为0,父子进程基于返回值走不同分支。实现代码如下,实际测试通过:

-
C 代码
void executeCommandAsyn(char* comand){
    int ret=vfork();
    if(ret==0)
    {
        int retGrandSon=vfork();
        if(retGrandSon==0){
            execl("/bin/bash", "bash", "-c",comand, (char *)0);
        }else{
            _exit(0);
        }
    }
    else{
        logger.error("vfork create son process with retcode : %d",ret);
        if(ret>0){
            if(waitpid(ret, NULL, 0) != ret)    /* wait for first child */
                {
                            logger.error("waitpid fail with return code %d",ret);
                }
        }
    }
}

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM