[分享] linux下system函数错误返回-1 错误原因NO child processes _VMware, Unix及操作系统讨论区_Weblogic技术|Tuxedo技术|中间件技术|Oracle论坛|JAVA论坛|Linux/Unix技术|hadoop论坛_联动北方技术论坛  
网站首页 | 关于我们 | 服务中心 | 经验交流 | 公司荣誉 | 成功案例 | 合作伙伴 | 联系我们 |
联动北方-国内领先的云技术服务提供商
»  游客             当前位置:  论坛首页 »  自由讨论区 »  VMware, Unix及操作系统讨论区 »
总帖数
7
每页帖数
101/1页1
返回列表
0
发起投票  发起投票 发新帖子
查看: 4908 | 回复: 6   主题: [分享] linux下system函数错误返回-1 错误原因NO child processes         上一篇   下一篇 
wzz
注册用户
等级:中士
经验:246
发帖:2
精华:0
注册:2012-3-16
状态:离线
发送短消息息给wzz 加好友    发送短消息息给wzz 发消息
发表于: IP:您无权察看 2016-4-14 14:37:13 | [全部帖] [楼主帖] 楼主

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

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

signal(SIGCHLD, SIG_IGN);

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

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

 

查看文本打印?

  1. typedef void (*sighandler_t)(int);  

  2. int pox_system(const char *cmd_line)  

  3. {  

  4.    int ret = 0;  

  5.    sighandler_t old_handler;  

  6.   

  7.    old_handler = signal(SIGCHLD, SIG_DFL);  

  8.    ret = system(cmd_line);  

  9.    signal(SIGCHLD, old_handler);  

  10.   

  11.    return ret;  

  12. }  

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

 

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

原文如下:

 

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


先看一下问题

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

  1. int pox_system(const char *cmd_line)

  2. {

  3.     return system(cmd_line);

  4. }

函数调用:

  1. int ret = 0;

  2. ret = pox_system("gzip -c /var/opt/I00005.xml > /var/opt/I00005.z");

  3. if(0 != ret)

  4. {

  5.     Log("zip file failed\n");

  6. }


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


糟糕的日志

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

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

  1. int ret = 0;

  2. ret = pox_system("gzip -c /var/opt/I00005.xml > /var/opt/I00005.z");

  3. if(0 != ret)

  4. {

  5.     Log("zip file failed: %s\n", strerror(errno)); //尝试打印出系统错误信息

  6. }



我们增加了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()函数:


  1. typedef void (*sighandler_t)(int);

  2. int pox_system(const char *cmd_line)

  3. {

  4.    int ret = 0;

  5.    sighandler_t old_handler;

  6.  

  7.    old_handler = signal(SIGCHLD, SIG_DFL);

  8.    ret = system(cmd_line);

  9.    signal(SIGCHLD, old_handler);

  10.  

  11.    return ret;

  12. }


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

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


  1. /* Ignore SIGCHLD to avoid zombie process */

  2. if (signal(SIGCHLD, SIG_IGN) == SIG_ERR) {

  3.     return -1;

  4. } else {

  5.     return 0;

  6. }


其他思考

我们公司的代码使用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();其用法在我的另一篇文章有介绍。





赞(0)    操作        顶端 
arcona
注册用户
等级:少校
经验:1100
发帖:10
精华:0
注册:2015-6-1
状态:离线
发送短消息息给arcona 加好友    发送短消息息给arcona 发消息
发表于: IP:您无权察看 2016-5-6 9:13:50 | [全部帖] [楼主帖] 2  楼

感谢分享~~



赞(0)    操作        顶端 
duff
注册用户
等级:少校
经验:968
发帖:0
精华:0
注册:2015-7-22
状态:离线
发送短消息息给duff 加好友    发送短消息息给duff 发消息
发表于: IP:您无权察看 2016-5-11 7:49:02 | [全部帖] [楼主帖] 3  楼

学习了



赞(0)    操作        顶端 
山友木樨
注册用户
等级:少校
经验:1040
发帖:9
精华:0
注册:2015-6-1
状态:离线
发送短消息息给山友木樨 加好友    发送短消息息给山友木樨 发消息
发表于: IP:您无权察看 2016-5-11 8:57:33 | [全部帖] [楼主帖] 4  楼



赞(0)    操作        顶端 
arcona
注册用户
等级:少校
经验:1100
发帖:10
精华:0
注册:2015-6-1
状态:离线
发送短消息息给arcona 加好友    发送短消息息给arcona 发消息
发表于: IP:您无权察看 2016-5-17 9:03:32 | [全部帖] [楼主帖] 5  楼

感谢楼主无私奉献~



赞(0)    操作        顶端 
twany
注册用户
等级:少校
经验:1408
发帖:17
精华:0
注册:2015-6-2
状态:离线
发送短消息息给twany 加好友    发送短消息息给twany 发消息
发表于: IP:您无权察看 2016-5-18 9:04:06 | [全部帖] [楼主帖] 6  楼

谢谢高手分享



赞(0)    操作        顶端 
Bobo226
注册用户
等级:上尉
经验:548
发帖:0
精华:0
注册:2020-1-7
状态:离线
发送短消息息给Bobo226 加好友    发送短消息息给Bobo226 发消息
发表于: IP:您无权察看 2022-9-26 11:39:06 | [全部帖] [楼主帖] 7  楼

玫瑰成为皇家花园和全国主要种植花卉。 在中国,玫瑰栽培的历史可以追溯到2000多年前的汉代。《西京杂记》中说,汉武帝的乐游苑中就栽有“玫瑰树”。在中国的玫瑰之乡平阴,早在唐朝就有翠屏山僧人种植玫瑰的传说。中国古人很早就能清楚地将蔷薇属植物分为至少7类品种:月季、玫瑰、蔷薇、缫丝花、木香、金樱子、荼蘼。“非关月季姓名同

 

不与蔷薇谱牒通,接叶连枝千万绿,一花两色浅深红。风流各自胭脂格,雨露何私造化工?别有国香收不得,诗人熏入水沉中。”南宋诗人杨万里这首《红玫瑰》,既写了玫瑰与月季、蔷薇的不同,又写了玫瑰的枝叶形态、深浅之色。从植物特征上看,月季和玫瑰差别不大,细加比较,两者确有不同。玫瑰茎部密生锐刺,一枝只开一朵花,花瓣直立

168won预测开奖  福彩3D稳赚方法  开奖网结果结果




赞(0)    操作        顶端 
总帖数
7
每页帖数
101/1页1
返回列表
发新帖子
请输入验证码: 点击刷新验证码
您需要登录后才可以回帖 登录 | 注册
技术讨论