一、功能
linux下在程序中调用shell命令实现某个功能,比如拷贝命令cp
二、使用
添加头文件 #include <stdlib.h>
函数原型 int system(const char *command);
描述说明是system的调用过程:
使用fork
创建一个子进程,子进程使用 execl
执行 command
中指定的 shell 命令system函数在子进程命令执行完成后返回在命令执行过程中,SIGCHLD
将被阻塞,SIGINT
和 SIGQUIT
将被忽略
由上面几点我们能够得到:
system
是一个阻塞函数,使用system
需等待命令执行结束后才会继续跑接下去的代码SIGCHLD
信号将被阻塞
本章的重点来了,为何要阻塞SIGCHLD
信号:
在Linux中fork
的子进程结束后,内核会向其父进程发送SIGCHLD
信号,即system
函数的调用者,system
源码中父进程是调用waitpid
函数来为变成僵尸的子进程进行回收,获得其结束状态,然后将这个结束状态返回给system
函数的调用者。
所以我们在调用system
之前不能去注册SIGCHLD
信号的处理函数,如在信号处理函数中进行wait
等操作,system
函数中的 waitpid
将可能获取不到子进程正确返回状态,因为子进程可能被信号处理函数抢先回收;
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
typedef void (*sighandler_t)(int);
int os_system(const char *cmd)
{
int ret = 0;
sighandler_t old_handler;
old_handler = signal(SIGCHLD, SIG_DFL);
ret = system(cmd);
signal(SIGCHLD, old_handler);
return ret;
}
int main(int argc, char *argv[])
{
char cmd[128] = "mkdir -p /data/param";
int ret = os_system(cmd);
if(ret == -1)
printf("mkdir erro");
else
printf("mkdir success");
}
old_handler =signal(SIGCHLD, SIG_DFL);
在调用system
前将SIGCHLD
信号的处理函数注册为SIG_DFL
,在Linux 中SIG_DFL
的作用就是忽略的意思;
signal(SIGCHLD, old_handler);
在调用完后将 SIGCHLD
的处理函数恢复成调用前的处理函数。