Linux进程等待

简介: Linux进程等待

什么是进程等待?

       进程等待是一种操作系统中的机制,它存在于父进程与子进程之间的关系。在一个进程创建了新的子进程后,这个父进程可能会需要等待子进程的完成,以收集子进程的资源和退出状态。


       在Linux系统中,wait函数和waitpid函数是用于实现进程等待的系统调用方法。wait函数会暂停当前进程的执行,直到一个子进程终止。当子进程终止后,wait函数会返回子进程的进程ID(PID),并将子进程的终止状态存储在指针status指向的变量中。


进程等待必要性

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


进程如何等待?

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 <stdlib.h>
  4 #include <sys/types.h>
  5 #include <sys/wait.h>
  6 
  7 //int status = 0;
  8 void Worker(int number)
  9 {
 10     int cnt = 5;
 11     while(cnt)
 12     {
 13         printf("I am child process, pid: %d, ppid: %d, cnt: %d, number: %d\n", getpid(), getppid()    , cnt--, number);
 14         sleep(1);
 15 
 16         //*p = 100;
 17         //int a = 10;
 18         //a /= 0;
 19     }
 20     exit(0);
 21 }                                                                              
 22                                                         
 23 int main()                      
 24 {                  
 25   pid_t id=fork();                                         
 26   if(id==0)                          
 27   {                  
 28     Worker(1);                          
 29   }else{               
 30     sleep(7);                                                                                     
 31     pid_t rid=wait(NULL);                                          
 32     if(rid==id)                                                  
 33     {                                                     
 34       printf("i am father process,pid:%d,ppid:%d rid: %d\n",getpid(),getppid(),rid);
 35     }                                               
 36   }                                           
 37   return 0;
 38 }    .

      进程等待,父进程必须在wait上进行阻塞等待,直到子进程僵尸状态,wait自动回收,因此父进程一般是最后退出的!

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

waitpid方法

pid_ t waitpid(pid_t pid, int *status, int options);
参数:
pid:
Pid=-1,等待任一个子进程。与wait等效。
Pid>0.等待其进程ID与pid相等的子进程。
status:
WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)
WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码。(查看进程的退出码)
options:
WNOHANG: 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若正常结束,则返回该子进
程的ID。

返回值

当正常返回的时候 waitpid 返回收集到的子进程的进程ID;

如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;

如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;


参数status

       参数status是一个指向整数的指针,用于保存被收集子进程的退出状态。他32bit,其中低16位为中储存着数据。需要注意的是status不能简单的当作整形来看待,可以当作位图来看待。他的返回值实际上如下图所示:

       对此,如果我们要读取正确的信息,需要将status右移动8位。需要注意的是:如果进程被杀死了,如上图所示,status是无意义的!

  1 #include <sys/wait.h>
  2 #include <stdio.h>
  3 #include<unistd.h>
  4 #include <stdlib.h>
  5 #include <string.h>
  6 #include <errno.h>
  7 int main( void )
  8 {
  9 pid_t pid;
 10 if ( (pid=fork()) == -1 )
 11 perror("fork"),exit(1);
 12 if ( pid == 0 ){
 13 int ct=5;
 14 while(ct--)
 15 {
 16   printf("i am a child process times:%d,pid:%d,ppid:%d\n",ct,getpid(),getppid());
 17   sleep(1);
 18 }
 19 sleep(5);                                                                              
 20 exit(11);
 21 } else {
 22 int st;
 23 int ret = waitpid(pid,&st,0);
 24 if ( ret > 0 && ( st & 0X7F ) == 0 ){ // 正常退出
 25 printf("child exit code:%d\n", (st>>8)&0XFF);
 26 } else if( ret > 0 ) { // 异常退出
 27 printf("sig code : %d\n", st&0X7F );
 28 }
 29 }
 30 }

正常退出情况:


非正常退出,被进程杀死情况,此时为进程的信号量:


WEXITSTATUS

WEXITSTATUS是一个宏,用于获取父进程中由子进程返回的退出状态。在C语言中,当一个进程通过调用exit()函数或_exit()函数来终止时,它会向其父进程返回一个整数值作为退出状态。

       WEXITSTATUS宏定义如下:

#define WEXITSTATUS(status) ((unsigned int)(status) >> 8)

  其中,status是子进程返回的退出状态。该宏将退出状态右移8位,以获取实际的退出状态值。

       使用WEXITSTATUS宏可以方便地获取子进程的退出状态,以便在父进程中进行进一步的处理或判断。

附加option选项

  1. WNOHANG:如果设置了这个选项,那么即使有子进程没有结束,waitpid也会立即返回,不会阻塞父进程。此时,waitpid函数会返回0,表示没有子进程已经结束。如果没有设置WNOHANG选项,那么waitpid会一直阻塞父进程,直到有一个子进程结束为止。
  2. WUNTRACED:如果设置了这个选项,那么即使子进程处于暂停状态(被暂停、停止或跟踪),waitpid也会返回。如果没有设置WUNTRACED选项,那么只有当子进程正常结束时,waitpid才会返回。
  3. WSTOPPED:如果设置了这个选项,那么只有当子进程处于暂停状态时,waitpid才会返回。如果没有设置WSTOPPED选项,那么只有当子进程正常结束时,waitpid才会返回。
  4. WCONTINUED:如果设置了这个选项,那么只有当子进程从暂停状态中恢复运行时,waitpid才会返回。如果没有设置WCONTINUED选项,那么只有当子进程正常结束时,waitpid才会返回。


       进程阻塞等待方式:

#include <sys/wait.h>
#include <stdio.h>
#include<unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main()
{
pid_t pid;
pid = fork();
if(pid < 0){
printf("%s fork error\n",__FUNCTION__);
return 1;
} else if( pid == 0 ){ //child
printf("child is run, pid is : %d\n",getpid());
sleep(5);
exit(257);
} else{
int status = 0;
pid_t ret = waitpid(-1, &status, 0);//阻塞式等待,等待5S
printf("this is test for wait\n");
if( WIFEXITED(status) && ret == pid ){
printf("wait child 5s success, child return code is :%d.\n",WEXITSTATUS(status));
}else{
printf("wait child failed, return.\n");
return 1;
}
return 0;
}
}

进程的非阻塞等待方式:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int main()
{
pid_t pid;
pid = fork();
if(pid < 0){
printf("%s fork error\n",__FUNCTION__);
return 1;
}else if( pid == 0 ){ //child
printf("child is run, pid is : %d\n",getpid());
sleep(5);
exit(1);
} else{
int status = 0;
pid_t ret = 0;
do
{
ret = waitpid(-1, &status, WNOHANG);//非阻塞式等待
if( ret == 0 ){
printf("child is running\n");
}
sleep(1);
}while(ret == 0);
if( WIFEXITED(status) && ret == pid ){
printf("wait child 5s success, child return code is :%d.\n",WEXITSTATUS(status));
}else{
printf("wait child failed, return.\n");
return 1;
}
}
return 0;
}


感谢你耐心的看到这里ღ( ´・ᴗ・` )比心,如有哪里有错误请踢一脚作者o(╥﹏╥)o!

相关文章
|
3天前
|
算法 Linux 编译器
技术笔记:LINUX2.6.32下的进程分析
技术笔记:LINUX2.6.32下的进程分析
|
2天前
|
监控 Linux 应用服务中间件
探索Linux中的`ps`命令:进程监控与分析的利器
探索Linux中的`ps`命令:进程监控与分析的利器
|
2天前
|
Web App开发 运维 监控
深入探索Linux命令pwdx:揭秘进程工作目录的秘密
`pwdx`命令在Linux中用于显示指定进程的工作目录,基于`/proc`文件系统获取实时信息。简单易用,如`pwdx 1234`显示PID为1234的进程目录。结合`ps`和`pgrep`等命令可扩展使用,如查看所有进程或特定进程(如Firefox)的目录。使用时注意权限、进程ID的有效性和与其他命令的配合。查阅`man pwdx`获取更多帮助。
|
3天前
|
存储 Shell Linux
Linux进程概念(下)
本文详细的介绍了环境变量和进程空间的概念及其相关的知识。
12 0
Linux进程概念(下)
|
2天前
|
监控 Linux
深入了解Linux的pmap命令:进程内存映射的利器
`pmap`是Linux下分析进程内存映射的工具,显示内存区域、权限、大小等信息。通过`/proc/[pid]/maps`获取数据,特点包括详细、实时和灵活。参数如`-x`显示扩展信息,`-d`显示设备。示例:`pmap -x 1234`查看进程1234的映射。注意权限、实时性和准确性。结合其他工具定期监控,排查内存问题。
|
3天前
|
网络协议 Linux Shell
技术笔记:Linux中的两种守护进程standalone和xinetd
技术笔记:Linux中的两种守护进程standalone和xinetd
|
3天前
|
监控 网络协议 关系型数据库
如何在Linux中查看正在运行的进程以及过滤特定端口和进程名称
如何在Linux中查看正在运行的进程以及过滤特定端口和进程名称
6 0
|
3天前
|
Linux
linux指令按端口查找和杀死进程
linux指令按端口查找和杀死进程
11 0
|
7天前
|
存储 Linux Shell
Linux进程概念(上)
冯·诺依曼体系结构概述,包括存储程序概念,程序控制及五大组件(运算器、控制器、存储器、输入设备、输出设备)。程序和数据混合存储,通过内存执行指令。现代计算机以此为基础,但面临速度瓶颈问题,如缓存层次结构解决内存访问速度问题。操作系统作为核心管理软件,负责资源分配,包括进程、内存、文件和驱动管理。进程是程序执行实例,拥有进程控制块(PCB),如Linux中的task_struct。创建和管理进程涉及系统调用,如fork()用于创建新进程。
26 3
Linux进程概念(上)
|
4天前
|
缓存 Linux Shell
【Linux】进程_1
【Linux】进程_1
8 1

热门文章

最新文章