调研popen/system, 理解这两个函数和fork的区别.

. 调研popen/system, 理解这两个函数和fork的区别. :
system()函数
函数原型

#include <stdlib.h>
int system(const char *command);

system()会调用fork()产生子进程,由子进程来调用/bin/sh-c string来执行参数string字符串所代表的命令,此命令执行完后随即返回原调用的进程。在调用system()期间SIGCHLD 信号会被暂时搁置,SIGINT和SIGQUIT 信号则会被忽略。
调用/bin/sh来执行参数指定的命令,/bin/sh 一般是一个软连接,指向某个具体的shell。

实际上system()函数执行了三步操作:
1.fork一个子进程;
2.在子进程中调用exec函数去执行command;
3.在父进程中调用wait去等待子进程结束。
返回值:
1>如果 exec 执行成功,即 command 顺利执行,则返回 command 通过 exit 或 return 的返回值。(注意 :command 顺利执行不代表执行成功,当参数中存在文件时,不论这个文件存不存在,command 都顺利执行)
2>如果exec执行失败,也即command没有顺利执行,比如被信号中断,或者command命令根本不存在, 返回 127
3>如果 command 为 NULL, 则 system 返回非 0 值.
4>对于fork失败,system()函数返回-1。
判断一个 system 函数调用 shell 脚本是否正常结束的方法的条件应该是
1. status != -1
2.(WIFEXITED(status) 非零且 WEXITSTATUS(status) == 0

  1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<stdlib.h>
  4 #include<string.h>
  5 int main(void)
  6 {
  7         int status=0;
  8         status=system("ls -l");
  9         if(status==-1){
 10                 perror("system()");
 11                 exit(1);}
 12         if(WIFEXITED(status)!=0)//正常退出{
 13                 if(WEXITSTATUS(status)==0)//操作正确{
 14                 printf("run command success\n");}
 15                 else{//操作错误
 16                         printf("run command fail and exit code is %d\n", WEXITSTATUS(status));
 17                 }
 18         }else//异常退出{
 19                 printf("exit code is  %d\n",  WEXITSTATUS(status));
 20         }
 21         return 0;
 22 }

这里写图片描述
popen()函数:创建一个管道用于进程间通信,并调用shell,因为管道被定义为单向的 所以 type 参数 只能定义成 只读或者 只写, 不能是 两者同时, 结果流也相应的 是只读 或者 只写.
函数原型:

  #include <stdio.h>

       FILE *popen(const char *command, const char *type);

       int pclose(FILE *stream);

`
函数功能:popen()会调用fork()产生子进程,然后从子进程中调用/bin/sh -c来执行参数command的指令。这个进程必须由 pclose 关闭。

command参数:
command 参数 是 一个 字符串指针, 指向的是一个 以 null 结束符 结尾的字符串, 这个字符串包含 一个 shell 命令. 这个命令 被送到 /bin/sh 以 -c 参数 执行, 即由 shell 来执行.

type 参数 也是 一个 指向 以 null 结束符结尾的 字符串的指针
参数type可使用“r”代表读取,“w”代表写入。
依照此type值,popen()会建立管道连到子进程的标准输出设备或标准输入设备,然后返回一个文件指针。
随后进程便可利用此文件指针来读取子进程的输出设备或是写入到子进程的标准输入设备中。
返回值:
若成功则返回文件指针,否则返回NULL,错误原因存于errno中

 #include<stdio.h>
  2 #include<string.h>
  3 #include<stdlib.h>
  4 int main()
  5 {
  6          FILE * file = NULL;
  7         char buf[1024]={0};
  8         file=popen("cat hello.c","r");
  9         if(file==NULL){
 10         perror("popen()");
 11         exit(1);}
 12         while(fgets(buf,1024,file)!=NULL){
 13                  fprintf(stdout, "%s", buf); }
 14         pclose(file);
 15         return 0;
 16 }

结果为:
这里写图片描述

区别
1.system 在执行期间,调用进程会一直等待 shell 命令执行完成(waitpid),但是 popen 无需等待 shell 命令执行完成就返回了。可以理解为,system为串行执行,popen 为并行执行。
2.popen 函数执行完毕后必须调用 pclose 来对所创建的子进程进行回收,否则会造成僵尸进程的情况。
3.popen 没有屏蔽 SIGCHLD ,如果我们在调用时屏蔽了 SIGCHLD ,如果在 popen 和 pclose 之间调用进程又创建了其他子进程并调用进程注册了 SIGCHLD 来处理子进程的回收工作,那么这个回收工作会一直阻塞到 pclose 调用。

猜你喜欢

转载自blog.csdn.net/xiaodu655/article/details/79717623
今日推荐