【Linux】进程控制(进程终止,进程等待)

目录

进程终止

进程终止是在做什么?

进程终止的三种情况

如何终止?

exit函数

_exit函数

进程等待

进程等待是什么?

为什么要有进程等待?

怎么使进程等待?

wait

waitpid

status


进程终止

进程终止是在做什么?

  1. 释放曾经的代码和数据所占空间
  2. 释放内核数据结构

进程终止的三种情况

  • 代码跑完,结果正确
  • 代码跑完,结果不正确
  • 代码执行时出现了异常,提前退出了
 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<sys/types.h>
  4 int main()
  5 {
  6     printf("I am fatherprocess, pid:%d,ppid:%d\n",getpid(),getppid());
  7     return 0;
  8 }

在main函数中:return 数值有什么意义?
     return 0;运行正常
     return 1,2,3,4.......一方面表示失败,另一方面表示失败原因。

                  (每个数值都有它对应的原因)

我们可以通过代码查询一下每个数值所代码的意义:

  1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<sys/types.h>
  4 #include<string.h>
  5 int main()
  6 {
  7     int errcode;
  8     for(errcode=0;errcode<=255;errcode++)
  9     {
 10         printf("%d:%s\n",errcode,strerror(errcode));
 11 
 12     }
 13 
 14     sleep(2);
 15     return 0;
 16 
 17 }

(1)那么我们如何查询我们运行的进程到底是成功了还是失败呢?

echo $?   :查看进程的退出码,通过退出码的数值来对应我们的进程是否运行成功;

注:退出码可以使用默认的,也可以自定义。

        如果是代码出现了异常,正如我们使用vs的时候,运行崩溃-------也就对应了OS发现了进程做了不该做的事情,OS杀掉该进程;

        所以在异常时,退出码也就没有意义了;

 (2)   那么我们就需要去寻找为什么出现了异常?原因是什么?

        进程出现异常,本质是因为进程收到了OS发给进程的信号!

        查找出现异常的原因我们可以用:kill -11 PID(退出信号)

(3)那么我们如何判断一个进程是异常的,还是代码跑完结果对,还是代码跑完结果不对?

1、先确认是否异常

2、不是异常,看退出码

注意:衡量一个进程退出:退出码,退出信号

如何终止?

  • main函数return表示终止(非main,return,函数结束)
  • 代码调用exit函数,(任意位置都可以exit)
  • _exit()  -------system call (系统调用)
exit函数

#include <unistd.h>
void exit(int status);

参数:status 定义了进程的终止状态,父进程通过wait来获取该值

_exit函数

#include <unistd.h>
void _exit(int status);

虽然status是int,但是仅有低8位可以被父进程所用。所以_exit(-1)时,在终端执行$?发现返回值是255。
 

对比一下下面两个代码的运行结果: 

我们会发现:有\n的会立即显示出hello ,但是没有的会等待一会才打印到屏幕上;

这是因为缓存区的原因;

如果在代码中分别加入exit(1)和_exit(1),我们会发现加exit也就是上面运行结果的第一种,会显示运行结果,但是加_exit不会显示除了hello;

        可以证明exit在进程退出时,会冲刷缓冲区,_exit不会冲刷缓冲区;

进程等待

进程等待是什么?

任何子进程在退出的情况下,一般必须要被父进程等待。进程在退出时,如果父进程不管不顾的话,退出进程会出现(Z)僵尸状态,从而造成内存泄漏

为什么要有进程等待?

1、父进程通过等待解决子进程的僵尸问题,回收系统资源

2、获取子进程的退出信息,知道子进程是通过什么圆心退出的(可选)

怎么使进程等待?

wait / waitpid

wait

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

pid_t wait(int*status);
返回值:
        成功返回被等待进程pid,失败返回-1。
参数:

        输出型参数,获取子进程退出状态,不关心则可以设置成为NULL

  1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<sys/types.h>
  4 #include<string.h>
  5 #include<stdlib.h>
  6 #include<sys/wait.h>
  7 
  8 int main()
  9 {
 10 
 11     printf("I am father process, pid:%d,ppid:%d\n",getpid(),getppid());
 12     pid_t id = fork();
 13     if(id==0)
 14     {
 15         int cnt=5;
 16         while(cnt)
 17         {
 18             printf("I am child process,pid:%d,ppid:%d,cnt:%d\n",getpid(),getppid()  ppid(),cnt);
 19             cnt--;
 20             sleep(1);
 21         }
 22         printf("child quit...\n");
 23         exit(0);
 24     }
 25     sleep(10);
 26     pid_t rid =wait(NULL);
 27 
 28     if(rid>0)
 29     {
 30         printf("wait sucess,rid:%d\n",rid);
 31     }
 32     sleep(3);
 33     printf("father quit...\n");
 34     return 0;
 35 }

通过ps来查看进程情况:

while :;do ps ajx | head -1 && ps ajx |grep myprocess | grep -v grep; sleep 1; done

我们会发现wait确实解决了(Z)僵尸问题。

waitpid

pid_ t waitpid(pid_t pid, int *status, int options);
返回值:
        当正常返回的时候waitpid返回收集到的子进程的进程ID;
        如果设置选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;
        如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;
参数:
        pid:
                Pid=-1,等待任一个子进程。与wait等效。
                Pid>0.等待其进程ID与pid相等的子进程。
        status:
                WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)
                WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码。(查看进程的退出码)
        options:
                WNOHANG: 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若正常结束,则返回该子进程的ID。

将wait代码中的pid_t rid =wait(NULL);改为pid_t rid = waitpid(-1,NULL,0);即可。运行结果一样。

status

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

status不能简单的当作整形来看待,可以当作位图来看待。(只研究低16位)

我们可以通过代码打印出status的退出码和退出信号。

      int status=0;
      pid_t rid = waitpid(-1,&status,0); 
  
      if(rid>0)
      {
          printf("wait sucess,rid:%d\n",rid);
      }
      else
      {
          printf("wait failed !\n");
      }
      sleep(3);
      printf("father quit,status:%d,child quit code:%d,child quit signal:%d\n",status,(status>>8)&0xFF,status&0x7F);

退出码:(status>>8)&0xFF

退出信号:status&0x7F

但是由于这种写法有点麻烦,我们还可以用宏:

WIFEXITED(status):退出信号

WEXITSTATUS(status):退出码

      int status=0;
      pid_t rid = waitpid(-1,&status,0);
  
  
      if(rid>0)
      {
          if(WIFEXITED(status))
          {
              printf("child quit sucess,child exit code:%d\n",WEXITSTATUS(status));
          }
          else{
              printf("child quit unnormal!\n");
          }
          printf("wait sucess,rid:%d\n",rid);
  
      }
      else
      {
          printf("wait failed !\n");
      }
阻塞等待,非阻塞等待

pid_t>0:等待成功,子进程退出了,且父进程回收成功

pid_t<0:等待失败

pid_t==0:检测成功了,只不过子进程还没有退出

阻塞等待:

         如果子进程没有退出,而父进程执行waitpid进程等待,为阻塞等待;

非阻塞等待:(WNOHANG)

        子进程还没有退出,父进程在等待时,允许父进程做一些其他的事情;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值