linux环境变量编程-进程资源回收

1. wait 函数资源回收

1.1 wait() 函数

父进程要负责阻塞(睡眠)进程,给子进程 回收资源,防止僵尸进程产生.

pid_t wait(int *status);
功能:父进程调用wait函数可以回收子进程终止信息。该函数有三个功能:
① 阻塞等待子进程退出
② 回收子进程残留资源
③ 获取子进程结束状态(退出原因)。

返回值:pid_t 成功会返回子进程的ID的号, 失败是-1
子进程的状态通过status返回,但是其值需要解析是否正常退出,以及退出时的值是多少.

1.2 宏:WIFEXITED和WEXITSTATUS

可以理解为wait函数的传入参数status,对于它的解析有两个宏,WIFEXITED只是个有分类范畴的宏,只判断真假正常与否.另一个宏WEXITSTATUS,就是解析出正常退出的值是多少.

WIFEXITED(status) 这个宏用来指出子进程是否为正常退出的,如果是,它会返回一个非零值。

WEXITSTATUS(status) 当WIFEXITED返回非零值时,我们可以用这个宏来提取子进程的返回值,如果子进程调用exit(5)退出,WEXITSTATUS(status)就会返回5;如果子进程调用exit(7),WEXITSTATUS(status)就会返回7。看下例子中的注释就明白此点的意思了.

如何更加容易的记住这些宏,IFEXITED意思就是if exited?是否正常退出.是正常退出的话,那么EXITSTATUS意思就是exit时的status值,正常退出时的状态值,W只是个标识前缀罢了.

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

int main(int argc, char const *argv[])
{
	pid_t pid = fork();
	//int pid  = 100;
	if(pid < 0){
		perror("fork");
		return -1;
	}
	else if(pid > 0){ 	//父进程
		//父进程要通过wait函数来对子进程进行回收
		int status;
		printf("父进程:pid = %d,ppid = %d\n",getpid(), getppid());

		pid_t pid = fork();	
		if(pid < 0){
			perror("fork");
			return -1;
		} 	
		else if(pid > 0){
			 //while(1)  //①打开之后等待所有子进程
			 //{
				int ret = wait(&status); //如果该进程没有子进程,wait会立即返回失败
										//回收子进程wait函数是否会引起阻塞???wait会阻塞,直到子进程执行完毕,返回。
				if(ret < 0){
					printf("wait 失败\n");
					return -1;
				}
				printf("父进程已wait到子进程%d, status = %d\n",ret, status);

				if(WIFEXITED(status)){//WIFEXITED(status) 子进程正常返回,则为真
					printf("子进程%d已正常退出,退出的值:status = %d\n", ret,WEXITSTATUS(status));//解析status获取子进程退出的各种状态
				} 
				else{
					printf("非正常退出\n");
				}
			 //}
		}	
		else if(0 == pid){
			sleep(2);
			printf("子进程2:pid = %d, ppid = %d\n", getpid(), getppid());
			exit(2);
		}
		//while(1);
	}
	else if(0 == pid) {//子进程
		sleep(3);
		printf("子进程1:pid = %d, ppid = %d\n", getpid(), getppid());
		exit(10);
	}
	return 0;
}

运行结果:
//说明的问题只有一个,就是wait只能等待一个子进程的退出,不能等待两个
通过以上结果,说明的问题只有一个,就是wait只能等待一个子进程的退出,不能等待两个.

将上述代码的注释 ① 处while(1)打开,会等待所有进程,最终的程序运行结果是:
在这里插入图片描述
最后wati失败,是因为所有子进程正常退出后,如果该进程没有子进程,wait会立即返回失败.

注意:如果一个父进程,一个子进程,子进程没有正常退出exit,父进程没有fork判断pid>0,但是此时WIFEXITED(status)还是会正常非0.因此,用这东西,就要子进程正常exit,然后父进程wait回收.

2. waitpid()函数资源回收

2.1 waitpid()函数

pid_t waitpid(pid_t pid, int *status, int options);

参数pid:父进程监听的子进程的进程号

  1. Pid = -1,等待任一个子进程。与wait等效。
  2. Pid > 0, 等待其进程ID与pid相等的子进程。

参数status:子进程的退出状态
参数options: 0 阻塞 / WNOHANG不阻塞

wait (&status) == waitpid (-1, &status , 0) ;

返回值:-1, 0, 大于0

  1. 若waitpid等到了正常终止的子进程,则返回该子进程的ID(即为大于0 的情况);
  2. 若设置了WNOHANG的值,而等不到正常退出的子进程,即返回0;
  3. 若设置了阻塞模式没有子进程,调用waitpid函数出错,则返回-1;
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

//pid_t process1;
int main(int argc, char const *argv[])
{

	pid_t pid1 = fork();
	if(pid1 < 0){
		perror("fork");
		return -1;
	}
	else if(0 == pid1){//子进程
		sleep(5);
		printf("子进程1:pid = %d, ppid = %d\n",getpid(), getppid());
		exit(10);
	}
	else if(pid1 > 0){//父进程
		printf("父进程:pid = %d, ppid = %d\n",getpid(), getppid());
		int stat = 0;
		pid_t pid2 = fork();
		if(pid2 < 0) {
			perror("fork");
			return -1;
		}
		else if(0 == pid2){
			sleep(3);
			printf("子进程2:pid = %d, ppid = %d\n",getpid(), getppid());
			exit(15);
		}
		else if(pid2 > 0){
			int ret = waitpid(-1, &stat, 0); 				//等同于wait ①
			//int ret = waitpid(pid1, &stat, 0); 			//等待特定pid进程 ②
			//int ret = waitpid(pid1, &stat, WNOHANG); 		//无阻塞回收,特定pid进程	③
			if(ret < 0){
				perror("waitpid ");
				return -1;
			}
			printf("父进程: ret = %d\n", ret);
			if(WIFEXITED(stat)){
				printf("正常退出,退出的值:status = %d\n", WEXITSTATUS(stat));
			} 
			else{
				printf("非正常退出\n");
			}
			sleep(5);
			printf("完结\n");
		 }
		
	}
	
	return 0;
}

运行结果如下:
在这里插入图片描述
注释②代码打开,关掉①,运行结果如下:
在这里插入图片描述
注释③代码打开,关掉①②,运行结果如下:
在这里插入图片描述

2.2 将waitpid设置成WNOHANG非阻塞,父进程一定要回收资源的用法如下:

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

int main(void)
{
	pid_t pid, wpid;
	int stat;
	wpid = waitpid(-1, &stat, WNOHANG);
	printf("first-pid: %d\n", wpid);
	pid=fork();
	if(pid < 0)
		printf("error occurred!\n");
	if(pid == 0){
		printf("child\n");
		sleep(5);
		exit(0);
	}
	printf("parent\n");
	wpid = waitpid(-1, &stat, WNOHANG);
	printf("second-pid: %d\n", wpid);
	sleep(7);
	wpid = waitpid(-1, &stat, WNOHANG);
	printf("third-pid: %d\n", wpid);
	exit(0);
}

运行结果如下:
在这里插入图片描述
第一次调用waitpid时:此时尚未有子进程,所以waitpid出错,返回-1;
第二次调用waitpid时:此时有子进程,但子进程尚未结束,由于waitpid设置为非阻塞的,所以waitpid返回0;
第三次调用waitpid时:此时有子进程,所以waitpid返回子进程id;

虽然waitpid可以设置成非阻塞的状态,但是如果父进程只调用一个waitpid,此时子进程没有结束,因此父进程就会直接略过不回收子进程的资源,因为waitpid只是返回了0,程序跑过去了,并没有回头.因此,如果非要用waitpid()或者wait()函数来回收子进程资源的话,势必会造成父进程的阻塞,waitpid非阻塞模式要么需要多调用很多次,并且sleep稍微等待一下,才能检测到子进程结束.但这样是不合理的,所以,个人感觉非阻塞模式,一般很少用.

虽然waitpid提供了wait所没有的三个特性:
1 waitpid使我们可以等待指定的进程,等待所有的进程.(但也是等第一个结束的子进程,不等待所有)
2 waitpid提供了一个无阻塞的wait
3 waitpid支持工作控制

综合所述,只需要记住waitpid阻塞回收特定进程的功能即可,其他无所谓.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值