system定义

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

首先要知道,system函数是c库中的函数,而不是系统调用。其实system函数使用起来并不复杂,难就难在对其返回值的理解。这个问题,下文会详细分析。参数的话,很简单,就是终端的命令即可。这是因为system函数的实现中调用了shell的缘故。

system优缺点

  • 优点:可以让c程序猿很方便地调用其他语言编写的程序,当然调用c程序自然也没问题;
  • 缺点:第一:效率低,第二:返回值难理解;

    效率低是因为system函数的实现过程至少要创建两个进程,一个是shell进程,还有一个或着多个shell命令运行的进程。所以在对效率高有要求的程序中,直接用fork和exec函数族比较合适;返回值的问题下文会讲;

system函数返回值

先写个简化版的system函数的实现过程。简化是没有考虑处理信号的问题。代码如下:

#include<unistd.h>
#include<sys/wait.h>
#include<sys/types.h> int system(char * command)
{
int status;
pid_t child; swicth(child = fork())
{
case -1:
return -1;
case 0:
execl("/bin/sh","sh","-c",command,NULL);
_exit(127);
default:
while(waitpid(child,&status,0)<0)
{
if(errno != EINTR)
{
status = -1;
break;
}
}
return status;
}
}

1)返回值为 “0” 或 “1”

这中情况一般不会出现,只有当写成system(NULL)时,才会出现这种结果。目的是为了检测系统的shell是否可用。返回1表示shell可用,返回0表示shell不可用;这种情况在上诉代码中看不出来,通过glibc库中的源码可以看出:

glibc-2.17/sysdeps/posix/system.c
int __libc_system(const char *line)
{
if(line == NULL)
return do_system("exit 0") == 0;
......
}

line指针指向的就是command命令行参数,system函数调用do_system系统调用,当执行“exit 0”(表示结束当前shell),执行成功do_system返回0,说明shell可用。反之,shell不可用。

2)返回值为 -1

有两个原因造成这样的结果。第一,因为fork创建子进程失败导致的。即“case -1”的情况,这中情况比较少见;第二,是不能正常处理子进程的“墓志铭”导致的,说白了,就是子进程的进程表在子进程结束时,没有经过父进程处理,而自己销毁了。这样的效果是因为父进程中安插的处理SIGCHLD信号的处理函数是SIG_IGN,或者用户设置了SA_NOCLDWAIT标志位导致,waitpid函数返回值为-1且全局变量errno的值为ECHLD;

例如:

signal(SIGCHLD,SIG_IGN); //出错的根源

if( (status = system(command)) < 0 )
{
fprintf(stderr,"system return %d (%s)\n",status,strerror(errno));
return -2;
}

所以在使用system函数时,一定要判断SIGCHLD是否被设置为SIG_IGN。

3)返回值为 _exit(127)的返回值

这种情况是因为程序运行到“case 0”中,execl函数执行失败后,执行_exit函数导致的。说明子进程无法执行shell该shell命令。

4)返回值为shell执行的进程的返回值

shell的终止状态是其执行最后一条命令的退出状态。这种情况下和获取子进程的退出状态一样。通过如下宏获取其退出状态:

  • WIFEXITED(status)
  • WEXITSATUS(status)
  • WIFSIGNALED(status)
  • WTERMSIG(status)
  • WCOREDUMP(satus)

综上所述,可以给出一个system函数返回值判断的例程:

if( (status == system(command))==-1 )
{
fprintf(stderr,"system() function return -1 (%s)\n",strerror(errno));
}
else if(WIFEXITED(status)&&WEXITSTATUS(status) == 127)
{
fprintf(stderr,"cannot invoke shell to exec command (%s)\n",strerror(enrrno));
}
else
print_wait_exit(status);

print_wait_exit函数就是上文中提到的获取shell退出状态的宏,根据需要去实现即可。

system函数和信号

影响system函数执行的信号有三个:SIGCHLD、SIGINT和SIGQUIT信号。

SIGCHLD信号:上文已经提过,它会影响waitpid函数,产生竞争现象的出现。调用system函数的进程可能还有其他的子进程,当然同样也会有wait或waitpid函数。当有SIGCHLD信号到来时,system函数中的waitpid函数和其他的wait或waitpid函数产生竞争状态,从而使得system执行异常。所以system执行期间会暂时屏蔽SIGCHLD信号;

SIGINT信号和SIGQUIT信号:调用system函数的进程会屏蔽这两个信号。system函数创建的进程会恢复这两个信号的默认处理状态。调用system函数的进程其实已经放弃了控制权,所以不能够去终止进程。反之,system函数创建的进程当然就有了控制权,所以要恢复控制权。

进程管理之system的更多相关文章

  1. UNIX环境编程学习笔记(22)——进程管理之system 函数执行命令行字符串

    lienhua342014-10-15 ISO C 定义了 system 函数,用于在程序中执行一个命令字符串.其声明如下, #include <stdlib.h> int system( ...

  2. C++ Windows进程管理

    功能: 1.各个进程启动.挂起.恢复.停止等 2.监听进程的运行状态,进程退出(正常.非正常)时,通知用户 3.异步队列 4.线程安全 进程管理器类: #ifndef __ProcessManager ...

  3. Android内存进程管理机制

    参考文章: http://www.apkbus.com/android-104940-1-1.htmlhttp://blog.sina.com.cn/s/blog_3e3fcadd0100yjo2.h ...

  4. Python::OS 模块 -- 进程管理

    os模块的简介参看 Python::OS 模块 -- 简介 os模块的文件相关操作参看 Python::OS 模块 -- 文件和目录操作 os模块的进程参数 Python::OS 模块 -- 进程参数 ...

  5. CentOS进程管理

    Linux系统中的基本运行单位是进程,通过对系统系统中的进程的管理能够对系统的实时运行状态进行了解和调度.Linux中提供了用于查看.调整和停止进程的命令.本文仍然以RHEL6说明Linux系统的进程 ...

  6. boost:进程管理

    概述 Boost.Process提供了一个灵活的C++ 进程管理框架.它允许C++ developer可以像Java和.Net程序developer那样管理进程.它还提供了管理当前执行进程上下文.创建 ...

  7. android145 360 进程管理

    package com.itheima.mobileguard.activities; import java.util.ArrayList; import java.util.List; impor ...

  8. psutil--跨平台的进程管理

    原文地址:http://www.jianshu.com/p/64e265f663f6 Python处理Windows进程 psutil(Python system and process utilit ...

  9. UNIX环境高级编程——进程管理和通信(总结)

    进程管理与通信 进程的管理 进程和程序的区别: 进程: 程序的一次执行过程   动态过程,进程的状态属性会发生变化 程序:存放在磁盘上的指令.数据的有序集合  是个文件,可直观看到 程序program ...

随机推荐

  1. eclipse中tomcat 中server location灰色,如何修改?

    Eclipse中tomcat service设置选择window ----show view---services可以看到服务的面板双击tomcat进入配置界面Service Locations(Sp ...

  2. Jenkins中的一些问题解决(~~不断更新~~)

    请使用ctrl+F,查询页面中你需要查找的错误信息(注意空格的输入) 1.错误"error fetching remote repo origin" 本地有多个sshkey,导致构 ...

  3. 数据结构基础:栈(Stack)

    什么是栈?     栈是限制插入和删除只能在同一个位置上进行的表,这个位置就是栈的顶端,对于栈的操作主要有三种形式:入栈(将元素插入到表中),出栈(将表最后的元素删除,也就是栈顶的元素),返回栈顶元素 ...

  4. ArrayList——源码探究

    摘要 ArrayList 是Java中常用的一个集合类,其继承自AbstractList并实现了List 构造器 ArrayList 提供了三个构造器,分别是 含参构造器-1 // 含参构造器-1 / ...

  5. 利用python发送邮件

    找了很多使用python发送邮件的文章, 发现写的并不是太全, 导致坑特别多, 刚把这个坑跨过去, 在此记录下来 本代码使用163作为发送客户端, 接收邮箱随意 首先登录163邮箱, 开启POP3/S ...

  6. python爬取百度搜索结果ur汇总

    写了两篇之后,我觉得关于爬虫,重点还是分析过程 分析些什么呢: 1)首先明确自己要爬取的目标 比如这次我们需要爬取的是使用百度搜索之后所有出来的url结果 2)分析手动进行的获取目标的过程,以便以程序 ...

  7. 18. leetcode 387. First Unique Character in a String

    Given a string, find the first non-repeating character in it and return it's index. If it doesn't ex ...

  8. DHCP服务的部署和配置

    DHCP介绍: DHCP(动态主机配置协议)是一个局域网网络协议,使用UDP协议工作,主要用途:给局域网络或网络服务供应商自动分配IP地址, DHCP有3个端口,其中UDP67和UDP68为正常的DH ...

  9. geotrellis使用(三十)使用geotrellis读取PostGIS空间数据

    前言 最近事情很多,各种你想不到的事情--such as singing and dancing--再加上最近又研究docker上瘾,所以geotrellis看上去似乎没有关注,其实我一直在脑中思考着 ...

  10. [STL] SET实用用法

    背景 今天考试深受平衡树之害,可以参见上一篇博客,想到了set却苦于实用的不熟练.同时QTY询问set的具体用法,所以写这篇博客,同时留作自用. 分类 参看了一下网上其他set博客,上来都是长篇大论概 ...