多进程编程之相关函数详解(wait,waitpid,system,popen)

wait()与waitpid()
当一个进程正常或异常退出时,内核就会向其父进程发送SIGCHLD信号。因为子进程退出是一个异步事件,所以这种信号也是内核向父进程发送的一个异步通知。父进程可以选择忽略该信号,或者提供一个该信号发生时即将被执行的函数,父进程可以调用wait()或waitpid()可以用来查看子进程退出的状态。

pid_t wait(int *status); pid_t waitpid(pid_t pid, int *status, int options);

在一个子进程终止前,wait使其调用者阻塞,而waitpid有一选项可使调用者不用阻塞。 waitpid并不等待在其调用的之后的第一个终止进程,他有若干个选项,可以控制他所等待的进程。 如果一个已经终止、但其父进程尚未对其调用wait进行善后处理(获取终止子进程的有关信息如CPU时间片、释放它锁占用的资源如文件描述符等)的进程被称僵死进程(zombie),ps命令将僵死进程的状态打印为Z。如果子进程已经终止,并且是一个僵死进程,则wait立即返回该子进程的状态。所以,我们在编写多进程程序时,最好调用wait()或waitpid()来解决僵尸进程的问题。

此外,如果父进程在子进程退出之前退出了,这时候子进程就变成了孤儿进程。当然每一个进程都应该有一个独一无二的父进程,init进程就是这样的一个“慈父”,Linux内核中所有的子进程在变成孤儿进程之后都会被init进程“领养”,这也意味着孤儿进程的父进程最终会变成init进程。

system()与popen()函数
如果我们在程序中,想执行另外一个Linux命令时,可以调用fork()然后再exec执行相应的命令即可,但这样相对比较麻烦。Linux系统提供了一个system()库函数,该库函数可以快速创建一个进程来执行相应的命令。

int system(const char *command);

譬如我们想执行ping命令,则可以使用下面的程序片段:

system("ping -c 4 -I eth0 4.2.2.2");
如果这里的 eth0、4.2.2.2 等是一个变量参数,我们则可以使用snprintf()格式化生成该命令:
char cmd_buf[256];
int count = 4;
char *interface="eth0";
char *dst_ip = "4.2.2.2";
snprintf(cmd_buf, sizeof(buf), "ping -c %d -I %s %s", count, interface, dst_ip);
system(cmd_buf);

对于之前我们使用fork()+execl()函数来执行ifconfig命令,并将该命令执行的结果写入到文件后再来读取的实现,这个过程相对比较麻烦,另外涉及到了创建文件和读取文件的过程。其实也有另外一个函数popen()可以执行一条命令,并返回一个基于管道(pipe)的文件流,这样我们可以从该文件流中一行样解析了。相应的代码如下:
vim popen.c

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
int get_ipaddr(char *interface, char *ipaddr, int ipaddr_size);
int main(int argc, char **argv)
{
 char ipaddr[16];
 char *interface="eth0";
 memset(ipaddr, 0, sizeof(ipaddr));
 if( get_ipaddr(interface, ipaddr, sizeof(ipaddr)) < 0 )
 {
 printf("ERROR: get IP address failure\n");
 return -1;
 }
 printf("get network interface %s IP address [%s]\n", interface, ipaddr);
 return 0;
}
int get_ipaddr(char *interface, char *ipaddr, int ipaddr_size) {
 char buf[1024];
 char *ptr;
 char *ip_start;
 char *ip_end;
 FILE *fp;
 int len;
 int rv;
 if( !interface || !ipaddr || ipaddr_size<16 )
 {
 printf("Invalid input arguments\n");
 return -1;
 }
 memset(buf, 0, sizeof(buf));
snprintf(buf, sizeof(buf), "ifconfig %s", interface);
 if( NULL == (fp=popen(buf, "r")) )
 {
 printf("popen() to excute command \"%s\" failure: %s\n", buf, strerror(errno));
 return -2;
 }
rv = -3; /* Set default return value to -3 means parser failure */
 while( fgets(buf, sizeof(buf), fp) )
 {
 if( strstr(buf, "netmask") )
 {
 ptr=strstr(buf, "inet");
 if( !ptr )
 {
 break;
 }
ptr += strlen("inet");
 while( isblank(*ptr) )
 ptr++;
 ip_start = ptr;
 while( !isblank(*ptr) )
 ptr++;
 ip_end = ptr;
 memset(ipaddr, 0, sizeof(ipaddr));
 len = ip_end-ip_start;
len = len>ipaddr_size ? ipaddr_size : len;
 memcpy(ipaddr, ip_start, len);
 rv = 0; /* Parser IP address OK and set rv to 0 */
 break;
 }
 }
 return rv;
}

运行结果如下:

get network interface eth0 IP address [192.168.2.17]

你可能感兴趣的:(多进程编程之相关函数详解(wait,waitpid,system,popen))