进程的等待

目录

一、进程等待必要性

二、进程等待的方法

1.wait

2.waitpid 

3.获取子进程status 

三、.小知识


一、进程等待必要性

        之前讲过,子进程退出,父进程如果不管不顾,就可能造成‘僵尸进程’的问题,进而造成内存泄漏。
        另外,进程一旦变成僵尸状态,kill -9 也无法再处理僵尸进程,因为谁也没有办法杀死一个已经死去的进程。
        最后,父进程派给子进程的任务完成的如何,我们需要知道。如,子进程运行完成,是否正常退出,如果正常退出结果对还是不对
        父进程通过进程等待的方式,回收子进程资源,获取子进程退出信息

二、进程等待的方法

1.wait

        #include<sys/types.h>
        #include<sys/wait.h>


        pid_t wait(int*status);

        随机等待一个子进程
        返回值:
                成功返回被等待进程pid,失败返回-1。
        参数:
                输出型参数,获取子进程退出状态,不关心则可以设置成为NULL。

2.waitpid 

        pid_ t waitpid(pid_t pid, int *status, int options);
        返回值:
        1.当正常返回的时候waitpid返回收集到的子进程的进程ID
        2.如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;
        3.如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;
        参数:
        pid:
        =-1,等待任一个子进程。与wait等效。
        >0.等待其进程ID与pid相等的子进程。

        (当我们一次性批量创建多个子进程时,就无法通过指定pid准确等待某个子进程了,因为后面fork返回的值会覆盖前面的返回值)
status:

        下面是两个宏
         WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)
        WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码。(查看进程的退出码)

        我们可以自行设置子进程exit()时候的退出码,这个退出码的含义由我们自己来定

//前面已经创建了一个进程,并已经退出,子进程的pid存放在id变量中
int status = 0;
pid_t ret = waitpid(id,&status, 0);
if(ret == id)//等待成功时会返回等待的子进程的pid
{
    if(WIFEXITED(status))
    {
        printf("进程是正常跑完的,退出码:%d\n",WEXITSTATUS(status));
     }
    else
    {
        printf("进程出现异常了\n");
    }
}
else
{
    printf("wait failed\n");
}

        这两个宏内部其实就是把status的值进行了位运算,以便更好地呈现给我们

 


options:

        即,设置父进程等待子进程的方式,常用有两种。

         第一种,options我们一般将它设置成0,让父进程阻塞等待

                等待的时候我们将父进程的pcb链入子进程pcb中维护的等待队列,原理和硬件的pcb中维护的一个等待队列相同,一个是等待子进程准备完毕,一个是等待硬件设备准备完毕

        第二种,将option设置成WNOHANG
                WNOHANG: 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若正常结束,则返回该子进程的ID

//前面已经创建了一个进程,并已经退出,子进程的pid存放在id变量中
int status = 0;
while(1)//可以通过while循环,来进行轮询
{
    pid_t ret = waitpid(id,&status, WNOHANG);//非阻塞地去等待
    if(ret > 0)
    {
        if(WIFEXITED(status))
        {
            printf("进程是正常跑完的,退出码:%d\n",WEXITSTATUS(status));
            break;
         }
         else
         {
            printf("进程出现异常了\n");
            break;
         }
     }
     else if(ret < 0)
     {
            printf("wait failed\n");
            break;
     }
     else
     {
            printf("子进程还未退出,继续等待\n");
     }
}

        而非阻塞轮询最重要的一点,是可以让父进程去做自己的事情

        如果子进程已经退出,调用wait/waitpid时,wait/waitpid会立即返回,并且释放资源,获得子进程退出信息。

        如果不存在该子进程,则立即出错返回-1。或者该进程不是其子进程,也会出错返回-1

3.获取子进程status 

       wait和waitpid,都有一个status参数,该参数是一个输出型参数,由操作系统填充。

        这里的status需要我们自己创建一个整型变量然后取地址传入wait。
        如果传递NULL,表示不关心子进程的退出状态信息。
        否则,操作系统会根据该参数,将子进程的退出信息反馈给父进程。


        status不能简单的当作整形来看待,可以当作位图来看待,具体细节如下图(只研究status低16比特位):

        信号的编号是从1开始的,为1-64.。因此0即为正常结束运行。从右往左第八位core dump标志现在不作讲解。

        子进程的pcb里面是有它对应的退出码和退出信号的

        父进程通过系统调用来读取子进程pcb。 

                我们这里的父进程想要获取子进程的退出码只能通过系统,即使我们定义了一个全局的status变量,在子进程所在代码内修改它,因为进程间具有独立性,所有父进程是无法看到经过子进程修改后的status变量的值的。

                同时也因为操作系统不相信任何人,所以它不允许用户直接访问操作系统内核的数据结构,万一你将它更改了呢?

三、.小知识

        循环查看进程状态

        我们可以先在上面的窗口右键复制一个会话

         例如我的可执行文件叫test.exe

        我们只需要替换下面test.exe的部分即可

        while :;do ps axj | head -1 && ps axj |grep test.exe |grep -v grep ; sleep 1;echo "---------------------";done

               
 

        通过复制的方式我们可以一边查看进程运行状态,一边查看进程的输出情况,还能够看相应的代码 

  • 28
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值