Linux下的系统编程——进程的执行与回收(八)

这篇具有很好参考价值的文章主要介绍了Linux下的系统编程——进程的执行与回收(八)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言:

前面我们对进程已经有了一个初步的了解与认识,现在让我们学习一下进程中一些函数的具体使用,比如exec可以执行一些指定的程序,wait / waitpid可以回收子进程,什么是孤儿进程,什么是僵尸进程,下面让我们一起对这些进行中的操作进行学习吧

目录

一、exec函数族

1.execlp:

  2.execl:

3.execvp

4.exec函数族的一般规律:

二、回收子进程

1.孤儿进程:

2 .僵尸进程:

​编辑

3.wait:

4.waitpid

 5.waitpid回收多个子进程


一、exec函数族

将当前进程的.text、.data替换为所要加载的程序的.text、.data,然后让进程从新的.text第一条指令开始执行,但进程ID不变换核丕换壳
 

Linux下的系统编程——进程的执行与回收(八),linux,wait,waitpid,exec,孤儿进程,僵尸进程,回收子进程

1.execlp:

    int execlp(const char *file, const char *arg, ...);        借助 PATH 环境变量找寻待执行程序

        参1: 程序名

        参2: argv0

        参3: argv1

        ...: argvN

        哨兵:NULL

该函数通常用来调用系统程序。如: ls、date、cp、cat等命令。
 

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

int main(int argc,char *argv[])
{
	int i;
	pid_t pid;        //创建子进程

	if(pid == -1){
		perror("fork error");
		exit(1);
	}else if(pid == 0){        //子进程
		//execlp("ls","-l","-d","-h",NULL);//错误写法

         /************************************/
		 execlp("ls","ls","-l","-h",NULL);    
         /************************************/

		perror("exec error");
		exit(1);
	}
	else if(pid > 0){        //父进程
		sleep(1);
		printf("I'm parent : %d\n",getpid());
	}
	return 0;
}

 Linux下的系统编程——进程的执行与回收(八),linux,wait,waitpid,exec,孤儿进程,僵尸进程,回收子进程

 date命令的实现:

execlp("date","date",NULL);

 Linux下的系统编程——进程的执行与回收(八),linux,wait,waitpid,exec,孤儿进程,僵尸进程,回收子进程

  2.execl:

 int execl(const char *path, const char *arg, ...);    自己指定待执行程序路径。(路径+程序名)

#include <stdio.h>


int main(int argc, char **argv)
{
	
	printf("Hello, %s!\n", argv[1]);
	
	printf("Hello, world!\n");
	
	return 0;
}

Linux下的系统编程——进程的执行与回收(八),linux,wait,waitpid,exec,孤儿进程,僵尸进程,回收子进程

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

int main(int argc,char *argv[])
{
	int i;
	pid_t pid;     //创建子进程

	if(pid == -1){
		perror("fork error");
		exit(1);
	}else if(pid == 0){    //子进程
		//execlp("ls","-l","-d","-h",NULL);
		//execlp("date","date",NULL);

         /************************************/
		 execl("./a.out","./a.out","linux",NULL);
         /************************************/

		perror("exec error");
		exit(1);
	}
	else if(pid > 0){    //父进程
		sleep(1);
		printf("I'm parent : %d\n",getpid());
	}
	return 0;
}

Linux下的系统编程——进程的执行与回收(八),linux,wait,waitpid,exec,孤儿进程,僵尸进程,回收子进程

3.execvp

加载一个进程,使用自定义环境变量env


int execvp(const char*file, const char *argv[]);

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

int main(int argc,char *argv[])
{
	int i;
	pid_t pid;            创建子进程

	if(pid == -1){
		perror("fork error");
		exit(1);
	}else if(pid == 0){        //子进程
		//execlp("ls","-l","-d","-h",NULL);
		//execlp("date","date",NULL);
		//execl("./a.out","./a.out","linux",NULL);
		
        /************************************/
		char *argv[] = {"date",NULL};
		execvp("date",argv);
        /************************************/

		perror("exec error");
		exit(1);
	}
	else if(pid > 0){         //父进程
		sleep(1);
		printf("I'm parent : %d\n",getpid());
	}
	return 0;
}

Linux下的系统编程——进程的执行与回收(八),linux,wait,waitpid,exec,孤儿进程,僵尸进程,回收子进程

4.exec函数族的一般规律:

        l:命令行参数列表

        p:使用PATH环境变量

        v:使用命令行参数数组

        exec函数一旦调试成功即执行新的程序,不返回。只要失败才返回,错误值-1。所以通常我们直接在exec函数调用后调用 perror()和exit()。无需if判断。· 

二、回收子进程

1.孤儿进程:

父进程死亡子进程进孤儿院

        孤儿进程:父进程先于子进程结束,则子进程成为孤儿进程,子进程的父进程成为init进程,称为init进程领养孤儿进程。
模拟孤儿进程:

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

int main(void)
{
    pid_t pid;
    pid = fork();

    if (pid == 0) {
        while (1) {
            printf("I am child, my parent pid = %d\n", getppid());
            sleep(1);
        }
    } else if (pid > 0) {
        printf("I am parent, my pid is = %d\n", getpid());
        sleep(9);
        printf("------------parent going to die------------\n");
    } else {
        perror("fork");
        return 1;
    }

    return 0;
}

 查看进程状态:ps ajx

Linux下的系统编程——进程的执行与回收(八),linux,wait,waitpid,exec,孤儿进程,僵尸进程,回收子进程

 进程孤儿院:

  1   2035   2035   2035 ?            -1 Ss    1001   0:00 /lib/systemd/systemd --user

 解决方法:

                 杀死子进程:     kill -9 4871

Linux下的系统编程——进程的执行与回收(八),linux,wait,waitpid,exec,孤儿进程,僵尸进程,回收子进程

2 .僵尸进程:

子进程死亡,父进程一直不管 

        僵尸进程:进程终止,父进程尚未回收,子进程残留资源(PCB)存放于内核中,变成僵尸(zombie)进程。(死亡以后没有回收)

        特别注意,僵尸进程是不能使用kill命令清除掉的。因为kill命令只是用来终止进程的,而僵尸进程已经终止。

模拟僵尸进程:

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

int main(void)
{
    pid_t pid;
    pid = fork();

    if (pid == 0) {
        printf("---child, my parent= %d, going to sleep 10s\n", getppid());
        sleep(10);
        printf("-------------child die--------------\n");
    } else if (pid > 0) {
        while (1) {
            printf("I am parent, pid = %d, myson = %d\n", getpid(), pid);
            sleep(1);
        }
    } else {
        perror("fork");
        return 1;
    }

    return 0;
}

  查看进程状态:ps ajx

Linux下的系统编程——进程的执行与回收(八),linux,wait,waitpid,exec,孤儿进程,僵尸进程,回收子进程

 解决方法:

        杀死父进程:   kill -9 4770

Linux下的系统编程——进程的执行与回收(八),linux,wait,waitpid,exec,孤儿进程,僵尸进程,回收子进程

*3.wait:

    wait函数:    回收子进程退出资源, 阻塞回收任意一个。

    pid_t wait(int *status)

    

    参数:(传出) 回收进程的状态。

    返回值:成功: 回收进程的pid

                   失败: -1, errno

    函数作用1:    阻塞等待子进程退出

    函数作用2:    清理子进程残留在内核的 pcb 资源

    函数作用3:    通过传出参数,得到子进程结束状态

    
    获取子进程正常终止值

        WIFEXITED(status) --》 为真 --》调用 WEXITSTATUS(status) --》 得到 子进程 退出值。

    获取导致子进程异常终止信号

        WIFSIGNALED(status) --》 为真 --》调用 WTERMSIG(status) --》 得到 导致子进程异常终止的信号编号。

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

int main(void)
{
    pid_t pid, wpid;
    int status;

    pid = fork();
    if (pid == 0) {
        printf("---child, my id= %d, going to sleep 10s\n", getpid());
        sleep(10);
        printf("-------------child die--------------\n");
        return 73;
    } else if (pid > 0) {
        //wpid = wait(NULL);          // 不关心子进程结束原因
        wpid = wait(&status);       // 如果子进程未终止,父进程阻塞在这个函数上
        if (wpid == -1) {
            perror("wait error");
            exit(1);
        }
        if (WIFEXITED(status)) {        //为真,说明子进程正常终止. 
            printf("child exit with %d\n", WEXITSTATUS(status));

        }
        if (WIFSIGNALED(status)) {      //为真,说明子进程是被信号终止.

            printf("child kill with signal %d\n", WTERMSIG(status));
        }

        printf("------------parent wait finish: %d\n", wpid);
    } else {
        perror("fork");
        return 1;
    }

    return 0;
}

正常终止:

Linux下的系统编程——进程的执行与回收(八),linux,wait,waitpid,exec,孤儿进程,僵尸进程,回收子进程

被信号终止:

Linux下的系统编程——进程的执行与回收(八),linux,wait,waitpid,exec,孤儿进程,僵尸进程,回收子进程

*4.waitpid

waitpid函数:    指定某一个进程进行回收。可以设置非阻塞。          

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

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

    

参数:
        pid:指定回收某一个子进程pid

            > 0: 待回收的子进程pid

            -1:任意子进程

            0:同组的子进程。

        status:(传出) 回收进程的状态。

        options:WNOHANG 指定回收方式为,非阻塞。

  

 返回值:

        > 0 : 表成功回收的子进程 pid

        0 : 函数调用时, 参3 指定了WNOHANG, 并且,没有子进程结束。

        -1: 失败。errno

回收任意子进程:

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

int main(int argc,char *argv[])
{
	int i;
	pid_t pid,wpid;
	for(i = 0;i < 5;i++){
		if(fork()==0)       //循环期间,子进程不fork
			break;
	}
	if(i == 5){           //父进程
        
        //wait(NULL);//一次wait/waitpid函数调用,只能回收一个子进程
        /*****************************************/
		wpid = waitpid(-1,NULL,WNOHANG);//回收任意子进程,没有结束的子进程,父进程直接返回0
        /****************************************/

		if(wpid == -1)
		{
			perror("waitpid error");
			exit(1);
		}
		printf("I'm parent ,wait a child finish :%d\n",wpid);
	}else{            //子进程,从break跳出
		sleep(i);
		printf("I'm %dth child\n",i+1);
	}
	return 0;
}


Linux下的系统编程——进程的执行与回收(八),linux,wait,waitpid,exec,孤儿进程,僵尸进程,回收子进程

回收指定进程:

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

int main(int argc,char *argv[])
{
	int i;
	pid_t pid,wpid,tmpid;
	for(i = 0;i < 5;i++){
		pid = fork();
		if(pid == 0){       //循环期间,子进程不fork
			break;
		}
        if(i == 2){
           	tmpid = pid;
			printf("*************pid= %d***************\n",pid);
		}
	}
	if(i == 5){           //父进程,从表达式2跳出
        sleep(5);		  //设置睡眠,等所有子进程结束后再回收

        //wait(NULL);	   //一次wait/waitpid函数调用,只能回收一个子进程
        //wpid = waitpid(-1,NULL,WNOHANG);     //回收任意子进程,没有结束的子进程,父进程直接返回0
		printf("I am parent , before waitpid , pid = %d\n",tmpid);

        /********将前面sleep(5)屏蔽***************/
		//wpid = waitpid(tmpid,NULL,0);         //指定一个进程回收,阻塞回收
        /****************************************/
        
        /*****************************************/
		wpid = waitpid(tmpid,NULL,WNOHANG);     //指定一个进程回收,不阻塞
        /****************************************/

		if(wpid == -1)
		{
			perror("waitpid error");
			exit(1);
		}
		printf("I'm parent ,wait a child finish :%d\n",wpid);	//wpid回收的是真正的子进程id
	}else{            //子进程,从break跳出
		sleep(i);
		printf("I'm %dth child,pid = %d\n",i+1,getpid());
	}
	return 0;
}

Linux下的系统编程——进程的执行与回收(八),linux,wait,waitpid,exec,孤儿进程,僵尸进程,回收子进程

注意:

        一次wait/waitpid调用只能回收一个子进程,无法回收他孙子辈的进程,多次清理需要while

 5.waitpid回收多个子进程

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

int main(int argc,char *argv[])
{
	int i;
	pid_t pid,wpid;
	for(i = 0;i < 5;i++){
		pid = fork();
		if(pid == 0){       //循环期间,子进程不fork
			break;
		}
	}
	if(i == 5){    //父进程
		/**********使用阻塞回收子进程********/

		while((wpid = waitpid(-1,NULL,0))){
			printf("wait child %d\n",wpid);
		}

		/***********************************/
	}else{        //子进程
		sleep(i);
		printf("I'm %dth child ,pid =%d\n",i+1,getpid());
	}

   	return 0;
}

结束一个回收一个

Linux下的系统编程——进程的执行与回收(八),linux,wait,waitpid,exec,孤儿进程,僵尸进程,回收子进程

之后返回-1,表示没有失败了

Linux下的系统编程——进程的执行与回收(八),linux,wait,waitpid,exec,孤儿进程,僵尸进程,回收子进程

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

int main(int argc,char *argv[])
{
	int i;
	pid_t pid,wpid;
	for(i = 0;i < 5;i++){
		pid = fork();
		if(pid == 0){       //循环期间,子进程不fork
			break;
		}
	}
	if(i == 5){
		/*********使用阻塞回收子进程***********/
		/*
		while((wpid = waitpid(-1,NULL,0))){
			printf("wait child %d\n",wpid);
		}
		*/
		/***********************************/
		
        /*******使用非阻塞方式回收子进程******/

		while((wpid = waitpid(-1,NULL,WNOHANG)) != -1){
			if(wpid > 0){	
				printf("wait child %d\n",wpid);
			}else if(wpid == 0){
				sleep(1);
				continue;
			}
        /************************************/

		}

	}else{
		sleep(i);
		printf("I'm %dth child ,pid =%d\n",i+1,getpid());
	}

   	return 0;
}

Linux下的系统编程——进程的执行与回收(八),linux,wait,waitpid,exec,孤儿进程,僵尸进程,回收子进程文章来源地址https://www.toymoban.com/news/detail-696842.html

到了这里,关于Linux下的系统编程——进程的执行与回收(八)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Linux】进程等待和替换——进程等待的原理、wait/waitpid方法、进程程序替换、进程替换原理、替换函数

    1.1进程等待的概念    进程等待指的是父进程等待子进程退出,以获取子进程的退出返回值,并释放子进程占用的资源。    当子进程先于父进程退出,但父进程没有关注子进程的退出状态时, 子进程会为了保存自己的退出状态而保持资源占用, 这种情况被称为“僵尸进

    2024年02月04日
    浏览(28)
  • Linux系统编程——进程间通信的学习

    学习参考博文: 进程间的五种通信方式介绍 Linux 信号介绍 Linux系统编程学习相关博文 Linux系统编程——文件编程的学习 Linux系统编程——进程的学习 Linux系统编程——线程的学习 Linux系统编程——网络编程的学习 常规学习Linux系统编程的内容是复杂且繁多的,不推荐刚开始

    2024年02月08日
    浏览(28)
  • Linux系统编程(终端和进程的关系)

    本篇文章带大家学习终端和进程的关系,终端相信大家都听过,那么真的理解终端是什么吗?应该有很多同学对于终端只是有一个模糊的概念。那么这篇文章就详细的来讲解一下终端的概念。 在Linux系统中,终端(Terminal)和控制台(Console)是两个不同的概念。它们都提供了

    2024年02月11日
    浏览(31)
  • Linux系统编程:采用管道的方式实现进程间通信

    目录 一. 进程间通信概述 二. 管道的概念  三. 通过管道实现进程间通信 3.1 实现原理 3.2 匿名管道创建系统接口pipe 3.3 管道通信的模拟实现 3.4 管道通信的访问控制规则 3.5 管道通信的特点 四. 通过匿名管道实现进程池 4.1 进程池的概念 4.2 进程池的模拟实现 五. 命名

    2024年02月12日
    浏览(30)
  • Linux--回收僵尸子进程:waitid,waitpid

    waitid: waitpid: 僵尸进程:至少要保留该进程的PCB信息。task_struct里面保留了任何进程退出时的退出结果信息!!! 故 waitid和waitpid的本质就是读取子进程的task_struct结构 示例: 运行结果: 退出信号 0 表示子进程正常退出,没有收到任何信号导致终止。在这种情况下,退出码可

    2024年02月16日
    浏览(28)
  • 『Linux从入门到精通』第 ⑰ 期 - 那年我手执『wait』桃木剑,轻松解决僵尸进程~

    🌸作者简介: 花想云 ,在读本科生一枚,C/C++领域新星创作者,新星计划导师,阿里云专家博主,CSDN内容合伙人…致力于 C/C++、Linux 学习。 🌸 专栏简介:本文收录于 Linux从入门到精通 ,本专栏主要内容为本专栏主要内容为Linux的系统性学习,专为小白打造的文章专栏。

    2024年02月16日
    浏览(38)
  • 【Linux系统编程】Linux下的编译器——gcc/g++的使用 及 动态库和静态库的认识

    这篇文章我们继续学习Linux中的开发工具,今天要学的是: Linux下的编译器——gcc/g++ 我们先来简单了解一下它们的概念: gcc (GNU Compiler Collection) 和 g++ 是 Linux 系统上最常用的编译器。它们是 GNU 组织开发的一套开源编译器工具集。 gcc: gcc 是 GNU 编译器集合中的 C 语言编译器。

    2024年02月16日
    浏览(34)
  • Linux高并发服务器开发---笔记1(环境搭建、系统编程、多进程)

    0613 首先这整个系列笔记属于笔记①:牛客校招冲刺集训营—C++工程师中的 第四章 笔记。 视频课链接: 视频1:Linux高并发服务器开发(40h); 视频2:第4章 项目制作与技能提升(录播)(26h30min); 视频课3: 第5章 高频考点与真题精讲(录播)中的 5.10-5.13 项目回顾 有个学

    2024年02月15日
    浏览(45)
  • 《Linux操作系统编程》 第六章 Linux中的进程监控: fork函数的使用,以及父子进程间的关系,掌握exec系列函数

    🌷🍁 博主 libin9iOak带您 Go to New World.✨🍁 🦄 个人主页——libin9iOak的博客🎐 🐳 《面试题大全》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺 🌊 《IDEA开发秘籍》学会IDEA常用操作,工作效率翻倍~💐 🪁🍁 希望本文能够给您带来一定的帮助🌸文章粗浅,敬

    2024年02月11日
    浏览(26)
  • Linux中并发程序设计(进程的创建和回收、exec函数使用)

    概念 程序 存放在磁盘上的指令和数据的有序集合(文件) 静态的 进程 执行一个程序所分配的资源的总称 动态的 进程和程序比较 注:进程是存在RAM中,程序是存放在ROM(flash)中的 进程内容 BSS段:存放程序中未初始化的全局变量 数据段:已初始化的全局变量,static声明的变

    2024年01月25日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包