Linux高级 2019-5-11上午

1.wait函数与waitpid函数

1.1 这两个函数的功能

  • 进程回收,对僵尸进程进行检测和回收

1.2 僵尸进程产生的原因

  • 子进程先于父进程终止,父进程没有对子进程进行回收,就会产生僵尸进程

1.3 在子进程回收时,内核会回收用户空间资源,同时系统对子进程的内核空间绝大多数资源进行回收释放,但是仍然会有 PCB 残留

  • PCB 不回收会对系统造成影响,可能导致创建进程失败。

1.4 编写一个僵尸进程

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
	pid_t pid;
	pid = fork();
	if(pid > 0)
	{
		printf("Parent Proc Running...\n");
		while(1);
	}
	else if(pid == 0)
	{
		printf("Child Proc Running...\n");
		sleep(5);
		exit(1);
	}
	else
	{
		perror("fork call error:");
		exit(1);
	}

	return 0;
}
  • 我们运行上述程序,在一个新终端中输入 ps aux 来查看当前的所有进出,找到 ./app 进程,发现有两个,这是我们创建出来的一对父子进程,在5秒后重新输入 ps aux 发现,子进程变为了 [app] ,这就是僵尸进程。

1.5 回收僵尸进程

  • 1.可以使用 kill 命令杀死僵尸进程;
  • 2.使用 wait 函数杀死僵尸进程;
    • 1.对于wait函数,需要两个头文件, sys/types.h 和 sys/wait.h ;
    • 2.函数形式: pid_t wait(int *status);
    • 3.返回值是被杀死的子进程的进程id;
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main()
{
	pid_t pid;
	pid_t wpid;
	pid = fork();
	if(pid > 0)
	{
		printf("Parent Proc Running...\n");
	}
	else if(pid == 0)
	{
		printf("Child Proc Running...\n");
		sleep(5);
		exit(1);
	}
	else
	{
		perror("fork call error:");
		exit(1);
	}
	wpid = wait(NULL);
	printf("%d has been killed.\n", wpid);

	return 0;
}
  • 3.可以使用 waitpid 函数杀死僵尸进程;
    • 1.函数形式: pid_t waitpid(pid_t pid, int *status, int options) ;
    • 2.对于 waitpid 的第一个参数:
      • pid > 0 时表示回收指定的子进程的资源;
      • pid = -1 时表示回收任意子进程的资源;
      • pid = 0 时表示回收当前调用进程同组的所有子进程;
      • pid < -1 时表示回收指定组的所有子进程;
    • 3.对于 waitpid 的第二个参数:传出子进程的终止原因,若不关心则设置为NULL;
    • 4.对于 waitpid 的第三个参数:通过 options 改变 waitpid 的工作方式,例如改为非阻塞轮询回收,一般传入 WNOHANG ,意为非阻塞。
    • 5.对于 waitpid 的返回值:
      • 没有任何子进程则返回 -1 ;
      • 没有可回收子进程返回 0 ;
      • 回收成功返回回收的进程的 pid ;
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main()
{
	pid_t pid;
	pid_t wpid;
	pid = fork();
	if(pid > 0)
	{
		printf("Parent Proc Running...\n");
	}
	else if(pid == 0)
	{
		printf("Child Proc Running...\n");
		sleep(5);
		exit(1);
	}
	else
	{
		perror("fork call error:");
		exit(1);
	}
	while((wpid=waitpid(-1, NULL, WNOHANG)) != -1)
	{
		if(wpid > 0)
			printf("%d has been killed.\n", wpid);
	}

	return 0;
}

2.exec族

2.1 使用 exec 族完成功能的重载,用某个程序的功能替换当前程序的功能

2.2 使用 exec 族函数

  • 1.首先使用 which 命令找到某个命令的路径(可执行文件所在的路径),本次使用的 firefox 火狐浏览器的可执行文件;
  • 2.编写使用 exec 族函数的代码;
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
	pid_t pid;
	pid = fork();
	if(pid > 0)
	{
		printf("Parent:%d process running...\n", getpid());
	}
	else if(pid == 0)
	{
		printf("Child:%d process running...\n", getpid());
		execl("/usr/bin/firefox", "firefox", "www.github.com", NULL);
	}
	else
	{
		perror("fork call error");
		exit(0);
	}

	return 0;
}

2.3 exec 族函数后缀的作用

  • 1.l :后缀含有 l 表示该函数的每一个参数都是字符串;
  • 2.p :默认在环境变量中查找程序位置;
  • 3.v :每一个参数都是数组中的元素;
  • 4.e :可以让被重载的进程构造新的环境变量;

2.4 exec 族函数有以下6个

  • int execl(const char* path, const char* arg, …
    /(char) NULL*/);
    • 这个函数的第一个参数是命令的路径(绝对路径),从第二个参数开始,依次为 命令 命令行参数 ,NULL,这里的NULL是哨兵,作用是让系统知道到此命令行参数结束;
  • int execlp(const char* file, const char* arg, …
    /(char) NULL*/);
    • 这个函数与第一个函数大致类似,只是第一个参数不同,这个函数的第一个参数为命令,不需要写全命令路径;
  • int execle(const char* path, const char* arg, …
    /, (char) NULL, char* const envp[]*/);
  • int execv(const char* path, char* const argv[]);
    • 这个函数的第一个参数为命令的绝对路径,第二个参数为一个字符串数组,该字符串数组是保存第一个函数从第二个参数开始到NULL的所有字符串;
  • int execvp(const char* file, char* const argv[]);
  • int execvpe(const char* file, char* const argv[],
    char* const envp[]);
  • 以上所有函数的底层函数都是 execve 函数,都是对这个函数的封装引用。

2.4 其他几个 exec 族函数的例子

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
	pid_t pid;
	pid = fork();
	char* argvs[] = {"firefox", "www.github.com", NULL};
	if(pid > 0)
	{
		printf("Parent:%d process running...\n", getpid());
	}
	else if(pid == 0)
	{
		printf("Child:%d process running...\n", getpid());
		// execl("/usr/bin/firefox", "firefox", "www.github.com", NULL);
		// execlp("firefox", "firefox", "www.github.com", NULL);
		execv("/usr/bin/firefox", argvs);
	}
	else
	{
		perror("fork call error");
		exit(0);
	}

	return 0;
}
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、下 4载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、下载 4使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、下载 4使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值