加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > Linux > 正文

LINUX教学:进程管理之system 详解

发布时间:2020-12-13 17:47:03 所属栏目:Linux 来源:网络整理
导读:《LINUX教学:进程管理之system 详解》要点: 本文介绍了LINUX教学:进程管理之system 详解,希望对您有用。如果有疑问,可以联系我们。 system定义 # include stdlib.h int system ( const char *command) ; 首先要知道,system函数是c库中的函数,而不是系统调

《LINUX教学:进程管理之system 详解》要点:
本文介绍了LINUX教学:进程管理之system 详解,希望对您有用。如果有疑问,可以联系我们。

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函数创建的进程当然就有了控制权,所以要恢复控制权.

本文永远更新链接地址

欢迎参与《LINUX教学:进程管理之system 详解》讨论,分享您的想法,编程之家PHP学院为您提供专业教程。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读