system返回值问题

linux——system的使用 可以看出,system是建立子进程来运行execl(system是封装后的execl函数)如果system()在调用/bin/sh时失败则返回127,其他失败原因返回-1。成功,则返回进程的状态值;不能执行时,返回127;cat config.txt能够发现LENG=9变成了LENG=5。用法:./changedata config.txt。编译运行:./a.out输入1。system函数api的使用。 阅读详情

调用system函数执行一个shell命令,返回-1,错误提示no child processes 但system可以执行成功

原因是调用system之前有放置忽略SIGCHLD的语句

signal(SIGCHLD, SIG_IGN);

如果SIGCHLD信号行为被设置为SIG_IGN时,waitpid()函数有可能因为找不到子进程而报ECHILD错误。似乎我们找到了问题的解决方案:在调用system()函数前重新设置SIGCHLD信号为缺省值,即signal(SIGCHLD, SIG_DFL)。

或者程序本身存在另一处waitpid调用,信号捕获只触发了一处导致system内部为捕获到CHILD信号而把系统全局errno置为10提示no child processes

解决办法 用pox_system()函数替代system(),只需要修改此处一个函数,其他调用处都不需要改。

typedef void (*sighandler_t)(int);  
int pox_system(const char *cmd_line)  
{  
   int ret = 0;  
   sighandler_t old_handler;  
  
   old_handler = signal(SIGCHLD, SIG_DFL);  
   ret = system(cmd_line);  
   signal(SIGCHLD, old_handler);  
  
   return ret;  
}  

SIG_DFL:默认信号处理程序
SIG_IGN:忽略信号的处理程序

测试过确实很奏效,感谢帖子的作者!
参考文章:http://my.oschina.net/renhc/blog/54582

原文如下:

今天,一个运行了近一年的程序突然挂掉了,问题定位到是system()函数出的问题,关于该函数的简单使用在我上篇文章做过介绍: http://my.oschina.net/renhc/blog/53580

先看一下问题

简单封装了一下system()函数:

int pox_system(const char *cmd_line)
{
    return system(cmd_line);
}

函数调用:

int ret = 0;
ret = pox_system("gzip -c /var/opt/I00005.xml > /var/opt/I00005.z");
if(0 != ret)
{
    Log("zip file failed\n");
}

问题现象:每次执行到此处,都会zip failed。而单独把该命令拿出来在shell里执行却总是对的,事实上该段代码已运行了很长时间,从没出过问题。

糟糕的日志

分析log时,我们只能看到“zip file failed”这个我们自定义的信息,至于为什么fail,毫无线索。

那好,我们先试着找出更多的线索:

int ret = 0;
ret = pox_system("gzip -c /var/opt/I00005.xml > /var/opt/I00005.z");
if(0 != ret)
{
    Log("zip file failed: %s\n", strerror(errno)); //尝试打印出系统错误信息
}

我们增加了log,通过system()函数设置的errno,我们得到一个非常有用的线索:system()函数失败是由于“ No child processes”。继续找Root Cause。

谁动了errno

我们通过上面的线索,知道system()函数设置了errno为ECHILD,然而从system()函数的man手册里我们找不到任何有关EHILD的信息。我们知道system()函数执行过程为:fork()->exec()->waitpid()。很显然waitpid()有重大嫌疑,我们去查一下man手册,看该函数有没有可能设置ECHILD:

ECHILD

(for waitpid() or waitid()) The process specified by pid (waitpid()) or idtype and id (waitid()) does not exist or is not a child of the calling process. (This can happen for one’s own child if the action for SIGCHLD is set to SIG_IGN. See also the Linux Notes section about threads.)

果然有料,如果SIGCHLD信号行为被设置为SIG_IGN时,waitpid()函数有可能因为找不到子进程而报ECHILD错误。似乎我们找到了问题的解决方案:在调用system()函数前重新设置SIGCHLD信号为缺省值,即signal(SIGCHLD, SIG_DFL)。我们很兴奋,暂时顾不上看Linux Notes部分,直接加上代码测试!乖乖,问题解决了!

如此处理问题是你的风格吗

正当我们急于check in 代码时,一个疑问出现了:“这个错误为什么以前没发生”?是啊,运行良好的程序怎么突然就挂了呢?首先我们代码没有改动,那么肯定是外部因素了。一想到外部因素,我们开始抱怨:“肯定是其他组的程序影响我们了!”但抱怨这是没用的,如果你这么认为,那么请拿出证据!但静下来分析一下不难发现,这不可能是其他程序的影响,其他进程不可能影响我们进程对信号的处理方式。

system()函数之前没出错,是因为systeme()函数依赖了系统的一个特性,那就是内核初始化进程时对SIGCHLD信号的处理方式为SIG_DFL,这是什么什么意思呢?即内核发现进程的子进程终止后给进程发送一个SIGCHLD信号,进程收到该信号后采用SIG_DFL方式处理,那么SIG_DFL又是什么方式呢?SIG_DFL是一个宏,定义了一个信号处理函数指针,事实上该信号处理函数什么也没做。这个特性正是system()函数需要的,system()函数首先fork()一个子进程执行command命令,执行完后system()函数会使用waitpid()函数对子进程进行收尸。

通过上面的分析,我们可以清醒的得知,system()执行前,SIGCHLD信号的处理方式肯定变了,不再是SIG_DFL了,至于变成什么暂时不知道,事实上,我们也不需要知道,我们只需要记得使用system()函数前把SIGCHLD信号处理方式显式修改为SIG_DFL方式,同时记录原来的处理方式,使用完system()后再设为原来的处理方式。这样我们可以屏蔽因系统升级或信号处理方式改变带来的影响。

验证猜想 

我们公司采用的是持续集成+敏捷开发模式,每天都会由专门的team负责自动化case的测试,每次称为一个build,我们分析了本次build与上次build使用的系统版本,发现版本确实升级了。于是我们找到了相关team进行验证,我们把问题详细的描述了一下,很快对方给了反馈,下面是邮件回复原文:

LIBGEN 里新增加了SIGCHLD的处理。将其ignore。为了避免僵尸进程的产生。

看来我们的猜想没错!问题分析到这里,解决方法也清晰了,于是我们修改了我们的pox_system()函数:

typedef void (*sighandler_t)(int);
int pox_system(const char *cmd_line)
{
    int ret = 0;
    sighandler_t old_handler;	
    old_handler = signal(SIGCHLD, SIG_DFL);
    ret = system(cmd_line);
    signal(SIGCHLD, old_handler);
    return ret;
}

我想这是调用system()比较完美的解决方案了,同时使用pox_system()函数封装带来了非常棒的易维护性,我们只需要修改此处一个函数,其他调用处都不需要改。

后来,查看了对方修改的代码,果然从代码上找到了答案:


/* Ignore SIGCHLD to avoid zombie process */
if (signal(SIGCHLD, SIG_IGN) == SIG_ERR) {
    return -1;
} else {
    return 0;
}

其他思考

我们公司的代码使用SVN进程管理的,到目前为止有很多branch,逐渐的,几乎每个branch都出现了上面的问题,于是我逐个在各个branchc上fix这个问题,几乎忙了一天,因为有的branch已被锁定,再想merge代码必须找相关负责人说明问题的严重性,还要在不同的环境上测试,我边做这些边想,系统这样升级合适吗?

首先,由于系统的升级导致我们的代码在测试时发现问题,这时再急忙去fix,造成了我们的被动,我想这是他们的一个失误。你做的升级必须要考虑到对其他team的影响吧?何况你做的是系统升级。升级前需要做个风险评估,对可能造成的影响通知大家,这样才职业嘛。

再者,据他们的说法,修改信号处理方式是为了避免僵尸进程,当然初衷是好的,但这样的升级影响了一些函数的使用方式,比如system()函数、wait()函数、waipid()、fork()函数,这些函数都与子进程有关,如果你希望使用wait()或waitpid()对子进程收尸,那么你必须使用上面介绍的方式:在调用前(事实上是fork()前)将SIGCHLD信号置为SIG_DFL处理方式,调用后(事实上wait()/waitpid()后)再将信号处理方式设置为从前的值。你的系统升级,强制大家完善代码,确实提高了代码质量,但是对于这种升级我不是很认同,试想一下,你见过多少fork()->waitpid()前后都设置SIGCHLD信号的代码?

使用system()函数的建议

上在给出了调用system()函数的比较安全的用法,但使用system()函数还是容易出错,错在哪?那就是system()函数的返回值,关于其返回值的介绍请见上篇文章。system()函数有时很方便,但不可滥用!

1、建议system()函数只用来执行shell命令,因为一般来讲,system()返回值不是0就说明出错了;

2、建议监控一下system()函数的执行完毕后的errno值,争取出错时给出更多有用信息;

3、建议考虑一下system()函数的替代函数popen();

信号量SIGCHLD的使用,如何让父进程得知子进程执行结束,如何让父进程区分多个子进程的结束 本教程基于 Ubuntu 20.10 gcc 10.2.0. 示例程序如果不能正常编译和执行,说明您系统和工具版本与我的不匹配,请自行查阅资料。 0 概述 先给出该信号的描述: Signal Value Description SIGCHLD 17 Child status has changed (POSIX). Signal sent to parent process whenever one of its child processes terminates or stops.Se 阅读详情

相关推荐

Linux系统搭建OpenClaw(原Clawdbot)全流程指南 最新版

工具定位:开源个人 AI 助手,支持文件读取、命令执行、多渠道交互(Telegram / 本地终端等);系统要求:主流 Linux 发行版(Ubuntu/Debian/CentOS 等),Node.js ≥22(核心依赖);安全提示:OpenClaw 为测试版,具备高权限操作能力,建议使用非主力机,配置权限白名单,避免接触敏感数据。

AI时代老码农的第二春 6562

system执行返回-1问题(执行fork失败问题)

背景 项目在一次升级版本后,发现在DSP发生异常后,没有生成dspcrash文件。该文件通过system函数,直接调用可执行程序。后来增加定位信息,发现system返回-1。而在串口上直接调用可执行程序,执行成功。在控制台调用system函数,返回-1。system函数在该处理器上必现调用失败。 定位 首先需要了解system的执行过程,实际上system执行了三步操作: fork一个子进程; 在子进程中调用exec函数执行command; 在父进程中调用wait等待子进程结束。 对于fork失败,sys

GeiGe123的博客 3651

零基础玩转华为AP 4050DN-HD:FAT模式家庭无线网络配置实战

本文为零基础用户提供华为AP 4050DN-HD从FIT模式转换为FAT模式的完整实战教程。详细介绍了固件升级、模式转换以及配置家庭无线网络(包括路由、DHCP、Wi-Fi和NAT)的每一步操作,帮助用户将企业级瘦AP改造为高性能家庭胖AP,打造稳定可靠的家庭网络环境。

weixin_29196613的博客 636

signal(SIGCHLD,SIG_DFL)和signal(SIGCHLD,SIG_IGN)的区别 默认忽略和主动忽略 为什么父进程前面父进程会产生僵尸进程而后面会杀死僵尸进程

signal(SIGCHLD,SIG_DFL)就是默认的忽略子进程结束信号,默认忽略子进程结束信号的作用就是产生了僵尸进程后可以让你在孩子死后进行wait操作来结束僵尸进程。 而主动进行signal(SIGCHLD,SIG_IGN)手动处理信号,操作系统会立即删除进程表中的子进程并且子进程死亡时,并不创建僵尸。由操作系统内核回收。 ...

qq_43502062的博客 2699

如何在RT-DETR-R18中修改ultralytics的yaml文件(附完整代码)

本文详细指导如何在RT-DETR模型中,通过修改Ultralytics框架的yaml配置文件,将Backbone从ResNet50轻量化替换为ResNet18。核心步骤包括自定义ResNet18基础模块、调整HybridEncoder的expansion参数至0.5,并协同修改检测头Decoder层数,最终提供完整的配置文件代码,助力开发者在资源受限环境下部署轻量级实时目标检测模型。

weixin_29091445的博客 290

STM32F407与AD7766实战:如何用SPI+DMA实现高速ADC数据采集(附完整代码)

本文详细介绍了如何利用STM32F407的SPI接口与DMA控制器,高效稳定地驱动24位高精度ADC芯片AD7766,实现高速连续数据采集。通过对比传统中断方式的瓶颈,阐述了SPI+DMA方案如何大幅降低CPU负载,并提供了从硬件设计、CubeMX配置到核心驱动代码的完整实战指南,帮助工程师解决高速ADC数据采集中的性能难题。

weixin_29281941的博客 190

system调用总是返回-1

在一个daemon程序中调用system来执行一段脚本,返回值总是-1.脚本简单的不能再简单了,只有一句exit 0,但还是返回-1. 查了很多资料,也没能找出原因,最后经过我反复的调试,终于发现了一个惊天动地的秘密!! 返回-1的原因是因为进程将SIGCHLD屏蔽了!! 确实我的程序在main函数里面就调用signal(SIGCHLD, SIG_IGN);将SIGCHLD屏蔽了!

herobox的专栏 1334

ClaudeCode 通过 CC Switch 配置 Ollama 本地大模型

本文介绍了如何让Claude Code使用本地免费模型qwen3.5:9b而无需Anthropic API Key的方法。主要内容包括:1)安装Claude Code、CC Switch代理工具和Ollama本地模型运行时;2)配置环境变量和设置文件将请求转发到本地服务;3)详细说明了系统架构和工作原理,展示请求如何从Claude Code经CC Switch代理到Ollama本地模型。该方案通过代理拦截和转发机制,实现了使用免费开源模型替代官方API的功能。

稚枭天卓 3224

Linux中system函数

在Linux系统中,system(),用于执行一个系统命令或者shell脚本。调用该函数之后,程序将启动一个新的Shell进程来运行指定的命令,并且等待命令执行完毕返回结果。

xiaowang_lj的博客 1479

开源人形机器人硬件生态:关键技术、产业链与低成本突破 | OpenLoong 社区线下分享会

本文将深入探讨人形机器人硬件平台的关键技术、产业链与核心部件以及降低成本的策略。从硬件平台的核心技术,到机器人核心零部件的详细介绍,再到产业链各环节的协同发展以及实现低成本化的创新思路,将一同剖析人形机器人迈向广泛应用所面临的挑战与机遇,展望其未来的发展趋势,为开发者和相关从业者提供一些参考与启示。

OpenLoong_的博客 2422

perl system函数返回值问题

在Perl脚本中,允许调用系统的命令来进行操作。这就是Perl灵活性的体现,作为一种系统命令的粘合语言,能给程序员带来许多的便利。这样,你就可以最大限度地利用别人的成果,用不着自己使劲造轮子了。在Perl中,可以用system、exec、readpipe这三个命令来调用其他脚本、系统命令等。这三个命令的主要区别就是返回值。1) 对于system这个函数来说,它会返回执行后的状态,比如说    @a...

kongjunlongaa的博客 7302

基于YOLOv26的道路抛洒物检测系统原理实现

本文提出了一种基于YOLOv26的道路抛洒物智能检测系统,通过深度学习技术实现道路抛洒物的实时检测与分类。系统采用分层架构设计,包含视频采集、目标检测、分类评估和预警处理等模块,能够自动识别轮胎碎片、货物包装、金属零件等多种抛洒物,并根据危险程度分级预警。YOLOv26算法在检测精度和速度上的优势使其特别适合道路监控场景,结合背景建模和运动目标提取技术,有效提高了复杂道路环境下抛洒物的识别率。该系统可集成到现有智能交通监控平台,为道路安全管理提供实时决策支持。

一键难忘的博客 1258

linux c system头文件,linux c system返回值问题总结

先看例子#include #include#include#includeintmain(){pid_t status;status= system("./test.sh");if (-1 ==status){printf("system error!");}else{printf("exit status value = [0x%x]\n", status);//status 低7bits表示导...

weixin_32616931的博客 526

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

linux system函数返回值问题

http://cooliron.blog.163.com/blog/static/124703138201310602355497/ system函数对返回值的处理,涉及3个阶段: 阶段1:创建子进程等准备工作。如果失败,返回-1。 阶段2:调用/bin/sh拉起shell脚本(备注),如果拉起失败或者shell未正常执行结束,原因值被写入到status的0~7比特位中。

xiaocai_36 985

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

linux c system结束进程,linux c system返回值问题总结

先看例子shell #include #include#include#includeintmain(){pid_t status;status= system("./test.sh");if (-1 ==status){printf("system error!");}else{printf("exit status value = [0x%x]\n", status);//status 低7...

weixin_42297349的博客 678

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

linux c system返回值问题总结

先看例子 #include <stdio.h> #include <stdlib.h> #include <sys/wait.h> #include <sys/types.h> int main() { pid_t status; status = system("./test.sh"); i...

weixin_30485291的博客 133

Linux下正确运用system函数以及理清返回值问题

在linux下想调用shell脚本,肯定对于使用system不陌生?但是使用system()函数一定要谨慎。必要要理清返回值问题以及调用机制。不然很容易造成程序的异常和bug等问题。 system函数介绍 system的作用是在shell终端执行command。简单的说就是在C中执行system(“pwd”)这行代码的含义就相当于在shell执行pwd一样。这么说还是比较通俗易懂的,下面详细描述system: #include <stdlib.h> int system(const char *

chen1415886044的博客 1399

解决perl 调用system返回值问题

<br />测试脚本如下:<br /> <br />my $run_app_path = "c://exit_value.pl";<br />my $ret_val = system( $run_app_path );<br />print "system value is : $ret_val/n";<br />$ret_val = $ret_val >> 8;<br />print "return value is : $ret_val/n";<br />exit 0;<br /> <br /> <br

我为编程狂,我为外语狂 5670

linux 系统信号忽略和system函数返回值问题(system的实现)

signal(SIGHUP, SIG_IGN); signal信号函数,第一个参数表示需要处理的信号值(SIGHUP),第二个参数为处理函数或者是一个表示,这里,SIG_IGN表示忽略SIGHUP那个注册的信号。 SIGHUP和控制台操作有关,当控制台被关闭时系统会向拥有控制台sessionID的所有进程发送HUP信号,默认HUP信号的action是 exit,如果远程登陆启动某个服务进程并在...

u014426028的博客 1021

system函数返回值问题(system的实现)—signal(SIGCHLD,SIG_DFL);signal(SIGNCHLD,S

http://hi.baidu.com/dooez/item/6cb5febbb88007ed4fc7fdef 1、关于在system中获取子进程的返回值与SIGCHLD 在Linux我们一般写的是Server程序,所以,一般在main函数中,首先将进程转换为后台进程,即调用deamon,deamon的一般实现,参见:: deamon的实现中会忽略下面的信号: signal

chengfangang的专栏 4680

system函数返回值问题(system的实现) 2.4 和2.6内核的差异

http://blog.163.com/xychenbaihu@yeah/blog/static/132229655201121944717783/   1、关于在system中获取子进程的返回值与SIGCHLD         在Linux我们一般写的是Server程序,所以,一般在main函数中,首先将进程转换为后台进程,即调用deamon,deamon的一般实现,参见:: http:

yangruibao的专栏 1245

python中os.system()的返回值

python中的os.system(cmd)的返回值与linux命令返回值(具体参见本文附加内容)的关系

渡江客涂鸦板 3万+

关于Perl使用system执行外部命令的返回值

问题及处理 最近做一个升级相关的任务,需要在Perl脚本中调用Python脚本,由于Perl脚本中的老代码都是使用的system()函数来调用Python脚本,我就直接仿写了,在Python中用sys.exit(n)退出。当Python返回5时,结果Perl拿到的却是1280,Perl函数调用如下: sub deploy_cert { my $appMode = getAppMod...

Hunk的菜鸟之路 4062

python os.system返回值_python os.system()返回值判断

最近遇到os.system()执行系统命令的情况,上网搜集了一下资料,整理如下,以备不时之需,同时也希望能帮到某些人。一、python中的 os.system(cmd)的返回值与linux命令返回值(具体参见本文附加内容)的关系大家都习惯用os.systemv()函数执行linux命令,该函数的返回值十进制数(分别对应一个16位的二进制数)。该函数的返回值与 linux命令返回值两者的转换关系为:...

weixin_34920313的博客 2428
上一篇: linux查看硬件信息
下一篇: debian系yum安装依赖rpm全部打包
HideInTime
博客等级 码龄9年 86粉丝 131原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值