您的位置:首页 > 运维架构 > Linux

十二、Linux系统编程-进程(五)SIGCHLD、wait、waitpid、system

2015-03-17 23:39 716 查看
一、SIGCHLD

当子进程退出的时候,内核会向父进程发送SIGCHLD信号,子进程的退出是个异步事件(子进程可以在父进程运行的任何时刻终止)
子进程退出时,内核将子进程置为僵尸状态,这个进程称为僵尸进程,它只保留最小的一些内核数据结构,以便父进程查询子进程的退出状态。
父进程查询子进程的退出状态可以用wait/waitpid函数

二、wait和waitpid
(1)、函数原型:
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
(2)、函数参数

status:该参数可以获得你等待子进程的信息

pid:要等待的进程id
pid < -1 :等待进程组id等于pid的绝对值中的任意一个进程
pid = -1:等待任意一个进程
pid > 0:等待进程id等于pid的进程

options:等待选项

WNOHANG       return immediately if no child has exited.

WUNTRACED   also return if a child has  stopped  

WCONTINUED (since Linux 2.6.10)also return if a stopped child has been resumed by deliveryof SIGCONT.

(3)、返回值
成功返回子进程id,失败返回-1

wait和waitpid之间的区别:

在一个子进程终止前, wait 使其调用者阻塞,而waitpid 有一选择项,可使调用者不阻塞。
waitpid并不等待第一个终止的子进程—它有若干个选择项,可以控制它所等待的特定进程。
实际上wait函数是waitpid函数的一个特例。

示例:
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>

#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)

int main(int argc,char* argv[])
{
int pid;
pid = fork();
if (pid == -1)
ERR_EXIT("fork error");
if (pid == 0)
{
sleep(3);
printf("this is child\n");
exit(2);
//abort();
}
printf("this is parent\n");
int status,ret;
ret = wait(&status);
if (ret == -1)
ERR_EXIT("wait error");
printf("ret=%d pid=%d\n",ret,pid);
if (WIFEXITED(status))
printf("child exit normaly,status=%d...\n",status);
if (WEXITSTATUS(status))
printf("exit status=%d\n",status);
return 0;
}
程序输出:
this is parent
this is child
ret=2832 pid=2832
child exit normaly,status=512...
exit status=512


三、僵进程与避免僵进程

        当一个子进程结束运行时,它与其父进程之间的关联还会保持到父进程也正常地结束运行或者父进程调用了wait才告终止。
进程表中代表子进程的数据项是不会立刻释放的,虽然不再活跃了,可子进程还停留在系统里,因为它的退出码还需要保存起来以备父进程中后续的wait调用使用。它将称为一个“僵进程”。

避免僵进程:

调用wait或者waitpid函数查询子进程退出状态,此方法父进程会被挂起。
如果不想让父进程挂起,可以在父进程中加入一条语句:signal(SIGCHLD,SIG_IGN);表示父进程忽略SIGCHLD信号,该信号是子进程退出的时候向父进程发送的。

四、system
(1)、函数声明:
#include <stdlib.h>
int system(const char *command);
(2)、函数参数
command:要执行的命令
(3)、返回值
如果无法启动shell运行命令,system将返回127;出现不能执行system调用的其他错误时返回-1。如果system能够顺利执行,返回那个命令的退出码。

实现自己的system函数,示例:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>

#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
int my_system(const char *command);
int main(int argc,char* argv[])
{
system("ls -l | wc -l");
my_system("ls -l | wc -l");
return 0;
}

int my_system(const char *command)
{
pid_t pid;
int status;
if (command == NULL)
return -1;
if ((pid = fork()) < 0)
status = -1;
else if (pid == 0)
{
execl("/bin/sh","sh","-c",command,NULL);
exit(127);
}
else
{
while(waitpid(pid,&status,0) < 0)
{
if (errno == EINTR)
continue;
status = -1;
break;
}
}
return status;
}
输出:
34
34
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: