进程的挂起,等待和退出(wait,waitpid,exit,_exit,atexit 等函数)

本文详细介绍了进程的挂起、等待(通过wait和waitpid函数)、退出(exit和_exit函数)以及清理函数(atexit)在嵌入式软件开发中的应用,包括原理、示例和注意事项,帮助开发者更好地管理进程生命周期。
摘要由CSDN通过智能技术生成

大家好,这里是小缺,一名对嵌入式软件开发充满热情的探索者。这一篇文章主要内容是带大家了解进程的挂起,等待,退出等操作。

1.1 进程的挂起

 #include <unistd.h>
  unsigned int sleep(unsigned int seconds);
  功能:进程在一定的时间内没有任何动作,称为进程的挂起(进程处于等待态)

 参数:
   seconds:指定要挂起的秒数
 返回值:
   若进程挂起到sec指定的时间则返回0,若有信号中断则返回剩余秒数

 注意: 
   进程挂起指定的秒数后程序并不会立即执行,系统只是将此进程切换到就绪态

案例

  #include <stdio.h>
  #include <unistd.h>
 
 int main(int argc, char const *argv[])
  {
     while(1)
     {
         printf("hello world\n");
 
         //当运行到sleep函数后,程序会在此位置等待设定的秒数,当秒数到大后,代
           码会接着执行
         // sleep运行时进程为等待态,时间到达后会先切换到就绪态,如果代码继续运
           行,再切换到运行态
        sleep(2);
     }
     
      return 0;
  }

现象就是每隔两秒打印一遍hello world

执行结果

1.2 程序的等待

wait 和 waitpid 是Unix和类Unix操作系统中的系统调用,它们用于让一个进程等待其子进程的结束,并回收子进程的资源。

1.2.1 wait 函数

#include <sys/types.h>
#include <sys/wait.h>
  pid_t wait(int *status);

 功能:等待子进程终止,如果子进程终止了,此函数会回收子进程的资源。

 调用wait函数的进程会挂起,直到它的一个子进程退出或收到一个不能被忽视的信号时才
被唤醒。

 若调用进程没有子进程或它的子进程已经结束,该函数立即返回。

参数:
 status:函数返回时,参数status中包含子进程退出时的状态信息。

 子进程的退出信息在一个int中包含了多个字段,
 用宏定义可以取出其中的每个字段
 子进程可以通过exit或者_exit函数发送退出状态

 返回值:
  成功:子进程的进程号
  失败:-1

取出子进程的退出信息

WIFEXITED(status)

如果子进程是正常终止的,取出的字段值非零。

WEXITSTATUS(status)

返回子进程的退出状态,退出状态保存在status变量的8~16位。 在用此宏前应先用宏WIFEXITED判断子进程是否正常退出,正常退出才可以使用此宏。 

注意: 此status是个wait的参数指向的整型变量。

案例

 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 
  int main()
  {
     pid_t pid;
     
     pid=fork();
     if(pid<0)
     {
         perror("fail to fork");
         return ‐1;
     }
     if(pid == 0)
    {
        int i = 0;
         for(i=0;i<5;i++)
         {
             printf("this is son process\n");
         }
 
         //使用exit退出当前进程并设置退出状态
         exit(2);
    }
    else 
   {
         
      //使用wait在父进程中阻塞等待子进程的退出
      //不接收子进程的退出状态
      //wait(NULL);
      //接收子进程的退出状态,子进程中必须使用exit或者_exit函数退出进程是发送退出状态    

       int status = 0;
       wait(&status);

      if(WIFEXITED(status) != 0)
      {
       printf("The son process return status: %d\n", WEXITSTATUS(status));
      }

       printf("this is father process\n"); 

   }
       return 0;
}

执行结果

1.2.2 waitpid 函数

  #include <sys/types.h>
  #include <sys/wait.h>
  pid_t waitpid(pid_t pid, int *status,int options)
  功能:等待子进程终止,如果子进程终止了,此函数会回收子进程的资源。

 参数:
 pid:指定的进程或者进程组
 pid>0:等待进程ID等于pid的子进程。
 pid=0:等待同一个进程组中的任何子进程,如果子进程已经加入了别的进程组,waitpid
不会等待它。
 pid=‐1:等待任一子进程,此时waitpid和wait作用一样。
 pid<‐1:等待指定进程组中的任何子进程,这个进程组的ID等于pid的绝对值
 status:保存子进程退出时的状态信息

 options:选项
 0:同wait,阻塞父进程,等待子进程退出。
 WNOHANG:没有任何已经结束的子进程,则立即返回。
 WUNTRACED:如果子进程暂停了则此函数马上返回,并且不予以理会子进程的结束状态

返回值:
 成功:返回状态改变了的子进程的进程号;如果设置了选项WNOHANG并且pid指定的进程存
在则返回0。
 失败:返回‐1。当pid所指示的子进程不存在,或此进程存在,但不是调用进程的子进
 程,waitpid就会出错返回,这时errno被设置为ECHILD。

  wait(status) <==> waitpid(‐1, status, 0)

案例

 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 
  int main(int argc, char *argv[])
  {
     pid_t pid;
     
    pid=fork();
     if(pid < 0)
     {
        perror("fail to fork");
        return ‐1;
     }
     if(pid == 0)
     {
         int i = 0;
         for(i=0;i<5;i++)
         {
             printf("this is son process\n");
             sleep(1);  
         }

             exit(0);
     }

    else 
    {    
     waitpid(pid, NULL, 0);
     printf("this is father process\n"); 
    }
    return 0;
 }

运行结果

如果没有 waitpid(),子进程的退出状态不会被父进程捕获,这可能会导致僵尸进程的产生。

僵尸进程是指已经结束但其退出状态还没有被父进程读取的进程。

这些僵尸进程在进程表中占据空间,直到父进程使用 wait() 或 waitpid() 读取它们的退出状态。

1.3 进程的终止

exit 和 _exit 是在Unix和类Unix操作系统中的两个不同的函数,它们都用于终止当前进程的执行

1.3.1 _exit函数

  #include <unistd.h>
  void _exit(int status);
  功能:退出当前进程
  参数: 
status:退出状态,由父进程通过wait函数接收这个状态
一般失败退出设置为非0
一般成功退出设置为0
  返回值:无

_exit 函数定义在 <unistd.h> 头文件中,是操作系统提供的一个低级终止函数。

当调用 _exit 时,它会立即终止当前进程,不执行任何高级清理操作,例如不调用退出处理函数或不刷新文件流。

因此,使用 _exit 函数可以实现更快的进程退出

1.3.2 exit函数

 #include <stdlib.h>
  void exit(int status);
  功能:退出当前进程
 参数:
    status:
退出状态,由父进程通过wait函数接收这个状态
    一般失败退出设置为非0
    一般成功退出设置为0
  返回值:无

exit 函数定义在 <stdlib.h> 头文件中,是标准C库提供的一个高级终止函数。

当调用 exit 时,它会执行以下操作:

  • 调用所有已注册的退出处理函数(通过 atexit 或 on_exit 注册)。
  • 关闭所有打开的文件流(如 fclose)。
  • 刷新所有输出缓冲区。
  • 调用 _exit 函数来终止进程,并传递给 _exit 一个退出状态(exit status)。

exit和_exit函数的区别:

exit为库函数,而_exit为系统调用

exit会刷新缓冲区,但是_exit不会刷新缓冲区

一般会使用exit

1.4 退出清理函数

 #include <stdlib.h>
 int atexit(void (*function)(void));
  功能:注册进程正常结束前调用的函数,进程退出执行注册函数
  参数:
    function:进程结束前,调用函数的入口地址。

 一个进程中可以多次调用atexit函数注册清理函数,
 正常结束前调用函数的顺序和注册时的顺序相反
 返回值:
    成功:0 
    失败:非0

 

注意事项

  • atexit 只能注册返回类型为 void、无参数的函数。
  • atexit 注册的函数不会接收任何参数。
  • 如果在 atexit 调用成功之后发生了错误(例如,程序异常退出),这些注册的函数可能不会被调用。
  • 在程序退出时,如果注册的函数执行失败,可能会影响到程序的退出状态。在Linux系统中,非零退出状态意味着程序异常终止。
  • atexit 函数是在程序终止时被调用的最后手段,它们是清理程序资源的最后机会。

 案例

 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 
  void clear_fun1(void)
  {
printf("perform clear fun1 \n");
  }
 
  void clear_fun2(void)
  {    
printf("perform clear fun2 \n");
  }
 
  void clear_fun3(void)
  {     
printf("perform clear fun3 \n");
  }
 
 int main(int argc, char *argv[])
  {
//atexit函数在进程结束时才会去执行参数对应的回调函数
//atexit多次调用后,执行顺序与调用顺序相反

 atexit(clear_fun1);
 atexit(clear_fun2);
 atexit(clear_fun3);
 printf("process exit 3 sec later!!!\n");
 sleep(3);

 return 0;
}

 执行结果

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值