目录

1、进程的执行

2、进程退出

3、僵尸态的回收

wait函数

注意

waitpid函数

功能

参数

返回值

wait & waitpid

阻塞调用

非阻塞调用

waitpid非阻塞调用指定具体pid

完整代码

进程小结


1、进程的执行

进程分为两种情况:

(1)做与父进程类似的事情

(2)做与父进程完全不同的事情,也就是运行新程序,即fork + exec。

那么exec又分为以下三种(具体如下链接)https://blog.csdn.net/2301_77695365/article/details/158569303?fromshare=blogdetail&sharetype=blogdetail&sharerId=158569303&sharerefer=PC&sharesource=2301_77695365&sharefrom=from_link

exec l

exec v

exec l p

exec v p

exec l  e

exec v p e

exec函数都是用新进程的各个段替代了当前进程的各个段。

我们又学习了myshell函数:shell程序,是一个命令行解释器,负责解释运行输入的命令。

2、进程退出

(1)正常退出

  • 从main函数返回
  • exit:会调用退出清理函数(atexit),处理IO缓存
  • _exit:不处理IO缓存

(2)异常退出

  • abort
  • signal:发信号

3、僵尸态的回收

wait函数

注意
  • wait函数是一个阻塞操作,它在 等 当前进程的任意子进程结束。
  • wait一次 只能 处理一个子进程
  • wait(int *wstatus);
  • exit(int status);

子进程的status这个参数在子进程函数结束后会传给父进程,而父进程可以通过wait函数或者waitpdi的wstatus来获得。

注意

要获得退出状态值,需要使用宏才能获取

  • WIFEXITED(wstatus):判断子进程是否是正常结束
  • WEXITSTATUS(wstatus):获取子进程退出状态
  • WIFSIGNALED(wstatus):判断子进程是否是信号结束的
  • WTERMSIG:获取结束的信号编号

使用宏的示例

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
int main(int argc, const char *argv[])
{
	printf("----test---fork---\n");
	pid_t pid = fork();
	if(pid<0)
	{
		perror("fork fail");
		return -1;
	}

	//父子进程都做
	printf("main pid:%d\n",pid);

	//父进程单独做的
	if(pid>0)
	{
		while(1)
		{
			printf("father pid:%d\n",getpid());
			sleep(1);
			int wstatus;
			if(wait(&wstatus)<0)//回收资源
			{
				perror("wait fail");
				return  -1;
			}
			//判断子进程是否是正常结束,因为这个参数在子进程结束后是传给父进程
			//而父进程可以通过wait函数或者waitpid的wstatus来获得
			if(WIFEXITED(wstatus)) 
			{
				//WEXITSTATUS获得取值码
				printf("child exit status:%d\n",WEXITSTATUS(wstatus));
			}
			//判断子进程是否是信号结束
			if(WIFSIGNALED(wstatus))
			{
                //WTERMSIG获取结束的信号编号
				printf("child exit signal:%d\n",WTERMSIG(wstatus));
			}
		}
	}
	
	//子进程单独做的
	else if(pid==0)
	{
		int i=0;
		while(i<5)
		{
			printf("child pid:%d\n",getpid());
			sleep(1);
			i++;
		}
		//子进程立刻停止循环,终止运行;
        //向父进程传递退出码99
		//父进程可以通过 waitpid() + WEXITSTATUS() 获取这个99
		//判断子进程的退出状态。
		exit(99);
	}
	return 0;
}

waitpid函数

  •  pid_t waitpid(pid_t pid, int *wstatus, int options);

功能
  • 等待子进程结束
参数
  • @pid

  • @wstatus:和wait的参数含义一样,可以用来保存子进程退出状态值
  • @options:选项为0表示waitpdi阻塞调用,选项为WNOHANG,表示非阻塞调用
返回值
  • 阻塞调用成功返回 对应子进程的pid,
  • 非阻塞被调用,如果子进程状态未改变,返回0
  • 失败返回-1

wait & waitpid

  • waitpid实现了一种非阻塞调用,可以指定某个具体的pid
  • wait(&status)等价于waitpid(-1,&status,0) 都是阻塞调用
阻塞调用

非阻塞调用

waitpid非阻塞调用指定具体pid

waitpid(1000,&status,0)阻塞等待pid为1000的子进程的状态改变

waitpid(1000,&status,WNOHANG)非阻塞等待pid为1000的子进程的状态改变

完整代码
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
int main(int argc, const char *argv[])
{
	printf("----test---fork---\n");
	pid_t pid = fork();
	if(pid<0)
	{
		perror("fork fail");
		return -1;
	}

	//父子进程都做
	printf("main pid:%d\n",pid);

	//父进程单独做的
	if(pid>0)
	{
		while(1)
		{
			printf("father pid:%d\n",getpid());
			sleep(1);
			int wstatus;
#if 0  // 阻塞调用
			//wait(&wstatus)等价于waitpid(-1,&(wstatus),0),这两个都是阻塞调用
			if(waitpid(-1,&wstatus,0)<0)//回收资源
			{
				perror("waitpid fail");
				return  -1;
			}
			//判断子进程是否是正常结束,因为这个参数在子进程结束后是传给父进程
			//而父进程可以通过wait函数或者waitpid的wstatus来获得
			if(WIFEXITED(wstatus)) 
			{
				//WEXITSTATUS获得取值码
				printf("child exit status:%d\n",WEXITSTATUS(wstatus));
			}
			//判断子进程是否是信号结束
			if(WIFSIGNALED(wstatus))
			{
				//WTERMSIG获取结束的信号编号
				printf("child exit signal:%d\n",WTERMSIG(wstatus));
			}
#endif

			//非阻塞调用
			pid_t ret_pid = waitpid(-1,&wstatus,WNOHANG);//回收资源
			if(ret_pid<0)
			{
				perror("waitpid fail");
				return -1;
			}
			printf("ret_pid:%d\n",ret_pid);
			if(ret_pid > 0)
			{
				if(WIFEXITED(wstatus))
				{
					printf("child exit status:%d\n",WEXITSTATUS(wstatus));
				}
				if(WIFSIGNALED(wstatus))
				{
					printf("child exit signal:%d\n",WTERMSIG(wstatus));
				}
			}
		}
	}
	
	//子进程单独做的
	else if(pid==0)
	{
		int i=0;
		while(i<5)
		{
			printf("child pid:%d\n",getpid());
			sleep(1);
			i++;
		}
		//子进程立刻停止循环,终止运行;
        //向父进程传递退出码99
		//父进程可以通过 waitpid() + WEXITSTATUS() 获取这个99
		//判断子进程的退出状态。
		exit(99);
	}
	return 0;
}

进程小结

1、进程的创建:fork

2、进程的执行

  • 做与父进程类似的事情:网络
  • 执行一个新程序:fork+exec

3、进程的退出

  • exit
  • _exit

4、退出状态

  • 孤儿进程
  • 僵尸进程

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐