• 关于linux下system()函数的总结


    导读 曾经的曾经,被system()函数折磨过,之所以这样,是因为对system()函数了解不够深入。这里必须要搞懂system()函数,因为有时你不得不面对它。

    linux-crond-1

    先来看一下system()函数的简单介绍:
    #include
    int system(const char *command)

    system()函数调用/bin/sh来执行参数指定的命令,/bin/sh 一般是一个软连接,指向某个具体的shell,比如bash,-c选项是告诉shell从字符串command中读取命令; 在该command执行期间,SIGCHLD是被阻塞的,好比在说:hi,内核,这会不要给我送SIGCHLD信号,等我忙完再说; 在该command执行期间,SIGINT和SIGQUIT是被忽略的,意思是进程收到这两个信号后没有任何动作。

    再来看一下system()函数返回值:

    为了更好的理解system()函数返回值,需要了解其执行过程,实际上system()函数执行了三步操作:

    1. fork一个子进程;
    2. 在子进程中调用exec函数去执行command;
    3. 在父进程中调用wait去等待子进程结束。 对于fork失败,system()函数返回-1。 如果exec执行成功,也即command顺利执行完毕,则返回command通过exit或return返回的值。 (注意,command顺利执行不代表执行成功,比如command:"rm debuglog.txt",不管文件存不存在该command都顺利执行了) 如果exec执行失败,也即command没有顺利执行,比如被信号中断,或者command命令根本不存在,system()函数返回127. 如果command为NULL,则system()函数返回非0值,一般为1.

    SYSTEMD

    看一下system()函数的源码

    看完这些,我想肯定有人对system()函数返回值还是不清楚,看源码最清楚,下面给出一个system()函数的实现:

    int system(const char * cmdstring)
    {
        pid_t pid;
        int status;
        if(cmdstring == NULL)
        {
            return (1); //如果cmdstring为空,返回非零值,一般为1
        }
        if((pid = fork())<0)
        {
            status = -1; //fork失败,返回-1
        }
        else if(pid == 0)
        {
            execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);
            _exit(127); // exec执行失败返回127,注意exec只在失败时才返回现在的进程,成功的话现在的
            进程就不存在啦~~
        }
        else //父进程
        {
            while(waitpid(pid, &status, 0) < 0)
            {
                if(errno != EINTR)
                {
                    status = -1; //如果waitpid被信号中断,则返回-1
                    break;
                }
            }
        }
        return status; //如果waitpid成功,则返回子进程的返回状态
    }

    仔细看完这个system()函数的简单实现,那么该函数的返回值就清晰了吧,那么什么时候system()函数返回0呢?只在command命令返回0时。

    看一下该怎么监控system()函数执行状态 这里给我出的做法:
    int status;
    if(NULL == cmdstring) //如果cmdstring为空趁早闪退吧,尽管system()函数也能处理空指针
    {
        return XXX;
    }
    status = system(cmdstring);
    if(status < 0)
    {
        printf("cmd: %s	 error: %s", cmdstring, strerror(errno)); // 这里务必要把errno信息输出或
        记入Log
        return XXX;
    }
    
    if(WIFEXITED(status))
    {
        printf("normal termination, exit status = %d
    ", WEXITSTATUS(status)); //取得cmdstring执行结果 }
        else if(WIFSIGNALED(status))
    {
        printf("abnormal termination,signal number =%d
    ", WTERMSIG(status)); //如果cmdstring被信号中
        断,取得信号值
    }
    else if(WIFSTOPPED(status))
    {
        printf("process stopped, signal number =%d
    ", WSTOPSIG(status)); //如果cmdstring被信号暂停执
        行,取得信号值
    }

    system()函数用起来很容易出错,返回值太多,而且返回值很容易跟command的返回值混淆。这里推荐使用popen()函数替代,关于popen()函数的简单使用可以自己查下资料。

    popen()函数较于system()函数的优势在于使用简单,popen()函数只返回两个值: 成功返回子进程的status,使用WIFEXITED相关宏就可以取得command的返回结果; 失败返回-1,我们可以使用perro()函数或strerror()函数得到有用的错误信息。

    这篇文章只涉及了system()函数的简单使用,还没有谈及SIGCHLD、SIGINT和SIGQUIT对system()函数的影响,事实上,之所以今天写这篇文章,是因为项目中因有人使用了system()函数而造成了很严重的事故。现像是system()函数执行时会产生一个错误:“No child processes”。此时调用my_system()来执行system函数的功能(my_system函数中是使用popen()函数来实现的), 测试了一天,没有再次出现程序突然死掉的问题(修改前连续循环调用system()函数测试,每10次就会至少导致程序挂掉一次.连续不停顿的调用)。

    本文地址:http://www.linuxprobe.com/linux-system-constructors.html

  • 相关阅读:
    在intent-filter中的配置
    利用asynchttpclient开源项目来把数据提交给服务器
    URL的应用
    ScrollView在布局中的作用
    android中传统的创建数据库
    for (Sms sms : smsLists){}
    Android中对文件的读写进行操作
    android中的5大布局
    android复制包需要修改的几个地方
    【Unity Tips】备忘录(扫盲篇)
  • 原文地址:https://www.cnblogs.com/linux130/p/5937305.html
Copyright © 2020-2023  润新知