P12 Linux进程编程wait进程挂起

前言    

                  

🎬 个人主页:@ChenPi

🐻推荐专栏1: 《Linux C应用编程(概念类)_@ChenPi的博客-CSDN博客》✨✨✨ 

🔥 推荐专栏2: 《C++_@ChenPi的博客-CSDN博客》✨✨✨

🛸推荐专栏3: ​​​​​​《链表_@ChenPi的博客-CSDN博客 》 ✨✨✨
🌺本篇简介  : 前两章我们学习了Linux进程如何创建子进程,这章我们学习一下父子进程的等等配合,以及获取子进程退出的信息

Linux 是一个多用户多任务的操作系统,每个用户可以同时运行多个程序

进程是程序运行的主体,包括进程的创建,调度和消亡的整个过程

当用户执行一个指令或者启动一个程序时,就创建了一个进程

一个运行的程序也可能有多个进程。

每个进程将被分配各种资源    

01 wait()函数

1.1 wait函数原型

对于许多需要创建子进程的进程来说,有时设计需要监视子进程的终止时间以及终止时的一些状态信 息,在某些设计需求下这是很有必要的。系统调用 wait()可以等待进程的任一子进程终止,同时获取子进程 的终止状态信息.

wait()函数原型如下所示:

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

函数参数和返回值含义如下:

  • status:参数 status 用于存放子进程终止时的状态信息,参数 status 可以为 NULL,表示不接收子进程 终止时的状态信息。
  • 返回值:若成功则返回终止的子进程对应的进程号;失败则返回-1。 

系统调用 wait()将执行如下动作:

  • 调用 wait()函数,如果其所有子进程都还在运行,则 wait()会一直阻塞等待,直到某一个子进程终 止;
  •  如果进程调用 wait(),但是该进程并没有子进程,也就意味着该进程并没有需要等待的子进程,那 么 wait()将返回错误,也就是返回-1、并且会将 errno 设置为 ECHILD。
  •  如果进程调用 wait()之前,它的子进程当中已经有一个或多个子进程已经终止了,那么调用 wait()也不会阻塞。wait()函数的作用除了获取子进程的终止状态信息之外,更重要的一点,就是回收子 进程的一些资源,俗称为子进程“收尸”。所以在调用 wait()函数之前,已经有子进程终止了,意味着正等待着父进程为其“收尸”,所以调用 wait()将不会阻 塞,而是会立即替该子进程“收尸”、处理它的“后事”,然后返回到正常的程序流程中,一次 wait()调用只能处理一次

1.2 wait()函数测试代码 

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>


int main(){
	int v_pid;   //获取子进程的id号
	int status;
	int pid = getpid();
	printf("pid : %d\n",pid);
	v_pid = fork();     //返回值为子进程的ID号
	int data=0;
	/* 父进程*/
	if(pid == getpid()){
		int Wait_ret = wait(&status);
		if(-1 == Wait_ret)
		{
			perror("wait error");
			exit(-1);
		}
		while(1){
			printf("this is father pid : %d\n",getpid());
			sleep(2);
		}
	}
	/* 子进程*/
	else if(v_pid == 0){
		while(1){
			printf("this is child pid : %d\n",getpid());
			sleep(2);
			data++;
			if(data == 3){//子进程执行次数达到三次,退出循环
				exit(0);
			}
		}
	}
	return 0;
}

示例代码中,fork创建子进程 ,当执行到父进程if(pid == getpid())的时候,调用了wait函数,wait()会一直阻塞等待,直到子进程执行完3次调用exit()退出子进程后,父进程才开始执行

 参数 status 不为 NULL 的情况下,则 wait()会将子进程的终止时的状态信息存储在它指向的 int 变量中, 可以通过以下宏来检查 status 参数:

1.3 wait参数宏定义:

  •  WIFEXITED(status):如果子进程正常终止,则返回 true;
  •  WEXITSTATUS(status):返回子进程退出状态,是一个数值,其实就是子进程调用_exit()或 exit()时指定的退出状态;wait()获取得到的 status 参数并不是调用_exit()或 exit()时指定的状态,可通过WEXITSTATUS 宏转换;
  •  WIFSIGNALED(status):如果子进程被信号终止,则返回 true;
  •  WTERMSIG(status):返回导致子进程终止的信号编号。如果子进程是被信号所终止,则可以通过 此宏获取终止子进程的信号;
  •  WCOREDUMP(status):如果子进程终止时产生了核心转储文件,则返回 true;

1.4  exit()退出子进程,wait()获取得到的 status 参数,WEXITSTATUS 宏转换

代码参考:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(){
	int v_pid;   //获取子进程的id号
	int status;
	int pid = getpid();
	printf("pid : %d\n",pid);
	v_pid = fork();     //返回值为子进程的ID号
	int data=0;
	/* 父进程*/
	if(pid == getpid()){
		int Wait_ret = wait(&status);
		printf("子进程退出,退出码为 %d\n",WEXITSTATUS(status));//解析子进程exit的退出码

		if(-1 == Wait_ret)
		{
			perror("wait error");
			exit(-1);
		}
		while(1){
			printf("this is father pid : %d\n",getpid());
			sleep(2);
		}
	}
	/* 子进程*/
	else if(v_pid == 0){
		while(1){
			printf("this is child pid : %d\n",getpid());
			sleep(2);
			data++;
			if(data == 3){//子进程执行次数达到三次,退出循环
				exit(0);
			}
		}
	}
	return 0;
}

02 waitpid()函数

使用 wait()系统调用存在着一些限制,这些限制包括如下:

  • 如果父进程创建了多个子进程,使用 wait()将无法等待某个特定的子进程的完成,只能按照顺序等 待下一个子进程的终止,一个一个来、谁先终止就先处理谁;
  • 如果子进程没有终止,正在运行,那么 wait()总是保持阻塞,有时我们希望执行非阻塞等待,是否 有子进程终止,通过判断即可得知;
  • 使用 wait()只能发现那些被终止的子进程,对于子进程因某个信号(譬如 SIGSTOP 信号)而停止 (注意,这里停止指的暂停运行),或是已停止的子进程收到 SIGCONT 信号后恢复执行的情况就 无能为力了。

2.1 waitpid()函数原型:

而设计 waitpid()则可以突破这些限制,waitpid()系统调用函数原型如下所示:

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

函数参数和返回值含义如下:

  • pid:参数 pid 用于表示需要等待的某个具体子进程,关于参数 pid 的取值范围如下:

    ⚫ 如果 pid 大于 0,表示等待进程号为 pid 的子进程;

    ⚫ 如果 pid 等于 0,则等待与调用进程(父进程)同一个进程组的所有子进程;

    ⚫ 如果 pid 小于-1,则会等待进程组标识符与 pid 绝对值相等的所有子进程;

    ⚫ 如果 pid 等于-1,则等待任意子进程。wait(&status)与 waitpid(-1, &status, 0)等价。

  • status:参数 status 用于存放子进程终止时的状态信息,参数 status 可以为 NULL,表示不接收子进程 终止时的状态信息。
  • options:
  • 返回值:若成功则返回终止的子进程对应的进程号;失败则返回-1,在参数 options 包含了 WNOHANG 标志的情况 下,返回值会出现 0,稍后介绍。

参数 options 是一个位掩码,可以包括 0 个或多个如下标志:

⚫ WNOHANG:如果子进程没有发生状态改变(终止、暂停),则立即返回,也就是执行非阻塞等 待,可以实现轮训 poll,通过返回值可以判断是否有子进程发生状态改变,若返回值等于 0 表示没 有发生改变。

⚫ WUNTRACED:除了返回终止的子进程的状态信息外,还返回因信号而停止(暂停运行)的子进 程状态信息;

⚫ WCONTINUED:返回那些因收到 SIGCONT 信号而恢复运行的子进程的状态信息。

 2.2 代码测试:waidpid函数非阻塞等待,并获取子进程的退出码,宏WUNTRACED

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(){
	int v_pid;   //获取子进程的id号
	int status;
	int pid = getpid();
	printf("pid : %d\n",pid);
	v_pid = fork();     //返回值为子进程的ID号
	int data=0;
	/* 父进程*/
	if(pid == getpid()){
		while(1){
			printf("this is father pid : %d\n",getpid());
			sleep(1);
			int Wait_ret =  waitpid(v_pid,&status,WNOHANG);  //非阻塞等待,获取子进程的退出码
			if(Wait_ret == v_pid)  //子进程退出后,返回值为本身id号
			{
				printf("子进程退出,退出码为 %d\n",WEXITSTATUS(status));//解析子进程exit的退出码
			}
		}
	}
	/* 子进程*/
	else if(v_pid == 0){
		while(1){
			printf("this is child pid : %d\n",getpid());
			sleep(1);
			data++;
			if(data == 3){//子进程执行次数达到三次,退出循环
				exit(0);
			}
		}
	}
	return 0;
}

 

  • 17
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@ChenPi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值