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