阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

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

60次阅读
没有评论

共计 2442 个字符,预计需要花费 7 分钟才能阅读完成。

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

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

先来看一下 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.

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

看一下 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\t error: %s", cmdstring, strerror(errno)); // 这里务必要把 errno 信息输出或
    记入 Log
    return XXX;
}

if(WIFEXITED(status))
{printf("normal termination, exit status = %d\n", WEXITSTATUS(status)); // 取得 cmdstring 执行结果 }
    else if(WIFSIGNALED(status))
{printf("abnormal termination,signal number =%d\n", WTERMSIG(status)); // 如果 cmdstring 被信号中
    断,取得信号值
}
else if(WIFSTOPPED(status))
{printf("process stopped, signal number =%d\n", 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 次就会至少导致程序挂掉一次. 连续不停顿的调用)。

阿里云 2 核 2G 服务器 3M 带宽 61 元 1 年,有高配

腾讯云新客低至 82 元 / 年,老客户 99 元 / 年

代金券:在阿里云专用满减优惠券

正文完
星哥说事-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2024-07-24发表,共计2442字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中