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”。表現出來就是在串口中看不到任何腳本里面的打印信息。