1. 程式人生 > >popen和system問題

popen和system問題

popen和system問題

1. 問題描述

C的程式碼裡面去呼叫命令啟動一個shell指令碼,分別使用了下面兩個途徑。 其中一個是: func1(cmd) { popen(cmd,type); pclose(); } 另一個是: func2() { system(cmd); } 其中cmd類似於“./xxx.sh &”。 問題就是,func1這種調法,會導致xxx.sh執行阻塞,指令碼最開始新增列印資訊都沒有顯示,但是top後顯示程序存在;而func2呼叫後腳本執行正常。

2. 問題分析

通過分析popen,pclose,system的原始碼,兩者的流程分別如下: 首先看popen,pclose的流程: 父程序呼叫popen, popen(cmd, type) { 返回一對fd(分別用來重定向子程序的讀和寫,但不是同時,根據type父程序和子程序最後分別只能用一個) fork 1. 子程序重定向fd,將標準輸出或者標準輸入定向到一個fd,然後執行execl cmd, 返回; 2. 父程序收到子程序返回的fd } 父程序呼叫pclose pclose { 1.等待popen出來的子程序結束; 2.關閉fd }   然後是system的流程: system { fork; 1. 子程序execv cmd; 2. 父程序wait子程序退出; 返回; }     上面的流程簡單點,總結出來就是摘自stackoverflow上的一個解釋: popen gives you a pair of file handles you can use to read and write input and output to and from stdin/stdout of the running process in an interactive manner. The system call is merely executing that and redirecting stdin of the current process to that of the invoked child process, and stdout of that process to stdout of the current (host) process. It depends what you are trying to achieve, in general. If your goal is simply to run a command, system works fine. If you're interested in reading its output in a programmatic manner and processing it (and possibly generating more input), then popen is going to work better.

子程序的標準輸入和標準輸出,和跟著開啟他的父程序的配置來的,當執行一個命令會後臺執行的時候,比如./test.sh &, 其實又是fork出來一個子程序,然而內部封裝的介面my_system介面中是連續呼叫的popen和pclose,這就導致了最終後臺執行起來的那個test.sh子程序,它裡面被popen中重定向的fd已經被關閉了,所以後面所有的echo列印都會報錯“broken pipe”。表現出來就是在串列埠中看不到任何腳本里面的列印資訊。

 

3. 問題總結

封裝一個popen和pclose連續呼叫的介面,對於執行不依賴任何標準輸入輸出的命令是可以使用的,但是實際上這樣做還不如直接呼叫system; 程式碼中頻繁呼叫system和popen這種系統呼叫都會有一個問題,就是程序的切換都會帶來效能上的一些開銷,這個是c和shell混合程式設計的一個隱患,所以專案後期還是需要儘量將shell指令碼中的業務整合進來,減少這種效能開銷,也減少這種類似的呼叫上的一些異常。