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

一、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



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值