linux c中system命令及其原理

最近工作中需要频繁的在代码中执行command,在linux c中,执行命令的方法多种多样,简单的记录一下这些方法和他们的一些区别。

原理

首先我们要明白在一个现有的进程中执行一个新的命令,并且继续执行原有进程的内容,本质上都是通过fork产生子进程,再用exec系列函数完成新的命令的执行的。我们可以用系统自带的一些函数实现这个效果,当然也可以根据原理,写出自己的函数满足各种其他的要求。

system()

最常见的大概就是system命令了,首先看一下system函数的源代码:

int system(const char * cmdstring)
{ 
  pid_t pid; 
  int status; 
  if(cmdstring == NULL)
  { 
    return (1); 
  } 
  if((pid = fork())<0)
  { 
    status = -1; 
  } 
  else if(pid = 0)
  {
    execl("/bin/sh", "sh", "-c", cmdstring, (char *)0); -exit(127);
  }
  else
  { 
    while(waitpid(pid, &status, 0) < 0)
    {
       if(errno != EINTER)
      {
         status = -1;
         break; 
      } 
    }
   } 
  return status; 
} 

流程其实很简单,首先fork出子进程,然后子进程通过execl通过sh命令执行传入的参数,父进程等待子进程退出后,返回错误码。当然这里要注意保证SIGCHLD信号没有ignore,否则waitpid会返回错误。
我们先看看构成system的基础函数:

exec…

system函数调用的是sh命令执行传入的参数,相当于我们使用默认的console输入命令的效果,system的本质还是通过exec执行sh,如果我们不需要终端,想直接运行某个可执行文件,那么我们直接写个函数调用exec就可以了。
exec说的并不是一个函数,而是一组函数,他们有着不同的输入参数。exec类的函数一旦被执行之后,该进程的代码段,数据,堆栈就都会被替换成新的进程的。所以说一旦调用了新的exec类函数,原有的进程出了pid不变,本身已经不存在了。exec函数就是我们在程序中执行命令这一步操作的基础。

fork

有了exec类函数,我们还缺一个能够让原本的进程能够正常运行的函数,那自然就是fork和forkv。system函数中使用的是fork函数。fork函数的作用大家都很清楚了,复制当前的进程,产生一个子进程,我们在子进程里执行exec,这样父进程就是我们原本的进程,子进程就是我们需要运行的指令。

fork和vfork

这两个函数功能类似都可以用来产生子进程。区别在于,vfork产生的子进程和父进程是共享地址空间的,因为在调用其他指令的时候,fork完立刻就会执行exec,这样复制父进程的数据就显得没有必要了,vfork显然会有更高的效率。此外由于数据的共享,在vfork的子进程调用exec或exit之前,父进程都是阻塞的。

改进一下?

system函数有几个特点,首先执行命令通过的是shell,并且需要等待指令执行完成之后才会返回。
根据上面所说的,我们可以进行一下改进:
使用vfork代替fork,可以降低系统资源的占用量。
通过两次fork的方法,可以不需要等待子进程完成,也不会产生僵尸进程。
(这次没有总结时间,以后想到了别的东西再补充吧)

点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注