zoukankan      html  css  js  c++  java
  • 进程管理之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)
    ",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)
    ",strerror(errno));
    }
    else if(WIFEXITED(status)&&WEXITSTATUS(status) == 127)
    {
    	fprintf(stderr,"cannot invoke shell to exec command (%s)
    ",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函数创建的进程当然就有了控制权,所以要恢复控制权。

  • 相关阅读:
    PNG文件格式具体解释
    opencv2对读书笔记——使用均值漂移算法查找物体
    Jackson的Json转换
    Java实现 蓝桥杯VIP 算法训练 装箱问题
    Java实现 蓝桥杯VIP 算法训练 装箱问题
    Java实现 蓝桥杯VIP 算法训练 单词接龙
    Java实现 蓝桥杯VIP 算法训练 单词接龙
    Java实现 蓝桥杯VIP 算法训练 方格取数
    Java实现 蓝桥杯VIP 算法训练 方格取数
    Java实现 蓝桥杯VIP 算法训练 单词接龙
  • 原文地址:https://www.cnblogs.com/cjaaron/p/7476706.html
Copyright © 2011-2022 走看看