头歌 进程管理之二(wait、exec、system的使用)

第1关:进程等待

任务描述


通过上一个实训的学习,我们学会了使用fork创建子进程,在使用fork创建子进程的时候,子进程和父进程的执行顺序是无法预知的。本关我们将介绍如何使得fork创建出来的子进程先执行,随后父进程再执行。

本关任务:学会在多进程中,学会进程的等待处理。

相关知识


在上一个实训的学习,我们知道使用fork可以创建一个进程,并且创建的子进程其执行顺序可能在父进程前,也可能在父进程后。因此,这是由于fork创建的进程是由操作系统调度器来决定执行顺序的。如果,当子进程在父进程前结束,则内核会把子进程设置为一个特殊的状态。这种状态的进程叫做僵死进程(zombie)。尽管子进程退出的时候,内核释放该进程所有的资源,包括打开的文件,占用的内存。但是仍然保留了一些信息(如进程号pid退出状态 运行时间等)。只有父进程获取了子进程的这些信息后,子进程才会彻底的被销毁,否则一直保持僵死状态。如果系统中产生大量的僵尸进程,将导致系统没有可用的进程号,从而导致系统不能创建新的进程。

Linux处理僵死进程的方法之一是使用进程等待的系统调用wait和waitpid来使得父进程获取子进程的终止信息。

wait函数和waitpid函数是系统调用函数,因此使用man 2 函数名来查看其使用方法。

wait函数使用方法


wait函数的具体的说明如下:

需要的头文件如下:

#include <sys/types.h>
#include <sys/wait.h>


wait函数格式如下:

pid_t wait(int *status);


参数说明:
参数status是一个整数指针,当子进程结束时,将子进程的结束状态字存放在该指针指向的缓存区。利用这个状态字,需要时可以使用一些由 Linux 系统定义的宏来了解子程序结束的原因。这些宏的定义与作用如下:

函数返回值说明: 调用成功时,返回值为被置于等待状态的进程的 pid;执行失败返回-1并设置错误代码errno。


案例演示1:


编写一个程序,使用fork函数与wait函数结合创建一个新进程,使得新创建的子进程在父进程前执行。详细代码如下所示:

#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main()
{pid_t pid;pid = fork();if(pid == -1){//创建进程失败printf("创建进程失败(%s)!\n", strerror(errno));return -1;}else if(pid == 0){//子进程sleep(2);printf("This is child process\n");exit(1);}else{//父进程int status;if(wait(&status) != -1){if(WIFEXITED(status))printf("子进程正常退出,退出代码:%d\n", WEXITSTATUS(status));}printf("This is parent process\n");exit(0);}
}

将以上代码保存为waitProcess.c文件,编译执行。可以看到执行waitProcess程序后,尽管子进程使用sleep睡眠了2秒,还是子进程先执行,然后父进程才执行。这就是wait的作用,使得父进程一直等待子进程执行结束后才继续执行。

waitpid函数使用方法


waitpid函数的具体的说明如下:

需要的头文件如下:

#include <sys/types.h>
#include <sys/wait.h>


waitpid函数格式如下:

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


参数说明: pid:用于指定所等待的进程。其取值和相应的含义如下所示:

参数option则用于指定进程所做操作。其取值和相应的含义如下所示:

参数status是一个整数指针,当子进程结束时,将子进程的结束状态字存放在该指针指向的缓存区。

函数返回值说明: 调用成功时,返回收集到的子进程的进程pid;当设置选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;执行失败返回-1并设置错误代码errno。


案例演示1:


编写一个程序,使用fork函数与waitpid函数结合创建一个新进程,使得新创建的子进程在父进程前执行。详细代码如下所示:

#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main()
{pid_t pid;pid = fork();if(pid == -1){//创建进程失败printf("创建进程失败(%s)!\n", strerror(errno));return -1;}else if(pid == 0){//子进程sleep(2);printf("This is child process\n");exit(1);}else{//父进程int status;if(waitpid(-1, &status, 0) != -1){if(WIFEXITED(status))printf("子进程正常退出,退出代码:%d\n", WEXITSTATUS(status));}printf("This is parent process\n");exit(0);}
}

将以上代码保存为waitpidProcess.c文件,编译执行。可以看到执行waitpidProcess程序后,尽管子进程使用sleep睡眠了2秒,还是子进程先执行,然后父进程才执行。waitpid函数可以实现与wait函数相同的功能。

编程要求


本关的编程任务是补全右侧代码片段中Begin至End中间的代码,具体要求如下:

补全waitProcess函数,等待子进程结束,并且返回子进程的退出的代码。


测试说明


本关的测试需要用户在右侧代码页中补全代码,然后点击评测按钮,平台会自动验证用户是否按照要求去检测结果。

开始你的任务吧,祝你成功!

解答:

#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>/************************* 返回值: 调用成功且子进程正常退出返回退出代码,否则返回-1
*************************/
int waitProcess()
{int status = -1;/********** BEGIN **********/pid_t pid;pid = fork();if(pid == -1){//创建进程失败return -1;}else if(pid == 0){//子进程sleep(2);printf("This is child process\n");exit(1);}else{//父进程int status;if(waitpid(-1, &status, 0) != -1){if(WIFEXITED(status))return WEXITSTATUS(status);}exit(0);}/********** END **********/return status;
}

第2关:进程创建操作-exec函数族

任务描述


在上一个实训中我们学习使用fork函数创建新进程,本关我们将介绍如何另一种创建新进程的库函数。

本关任务:学会使用C语言在Linux系统中使用exec族的系统调用创建一个新的进程。

相关知识


在上一个实训中提到,fork函数创建的子进程可以通过调用exec函数族来正确退出。其原理是,使用exec函数族可以执行一个新的程序,并且以新的子进程来完全替换原有的进程地址空间。

exec函数族的作用是根据指定的文件名找到可执行文件,并用它来取代调用进程的内容,换句话说,就是在调用进程内部执行一个可执行文件。这里的可执行文件既可以是二进制文件,也可以是任何Linux下可执行的脚本文件。

通常exec函数族用来与fork函数结合一起使用。使用fork函数创建一个子进程,然后在子进程中使用exec函数族来执行一个新的程序。当在由fork创建的子进程中使用exec函数族来执行新程序时,子进程的地址空间会被新执行的程序完全覆盖,并且此时fork的父进程与子进程地址空间被分离开,也就是使用exec函数族创建的新程序不会对fork的父进程造成任何影响。

exec函数族是库函数,因此使用man 3 exec来查看其使用方法。

使用exec函数族创建进程


exec函数族的具体的说明如下:

需要的头文件如下:

#include <unistd.h>


函数族格式如下:

int execl(const char *path, const char *arg, ... /* (char  *) 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[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[],  char *const envp[]);


参数说明:
1、函数名中含有字母l的函数,其参数个数不定。其参数由所调用程序的命令行参数列表组成,最后一个NULL表示结束。

2、函数名中含所有字母v的函数,则是使用一个字符串数组指针argv指向参数列表,这一字符串数组和含有l的函数中的参数列表完全相同,也同样以NULL结束。
3、函数名中含有字母p的函数可以自动在环境变量PATH指定的路径中搜索要执行的程序。因此它的第一个参数为file表示可执行函数的文件名。而其他函数则需要用户在参数列表中指定该程序路径,其第一个参数path 是路径名。路径的指定可以是绝对路径,也可一个是相对路径。但出于对系统安全的考虑,建议使用绝对路径而尽量避免使用相对路径。
4、函数名中含有字母e的函数,比其他函数多含有一个参数envp。该参数是字符串数组指针,用于制定环境变量。调用这两个函数时,可以由用户自行设定子进程的环境变量,存放在参数envp所指向的字符串数组中。这个字符串数组也必须由NULL结束。其他函数则是接收当前环境。


函数返回值说明: 只有当函数执行失败时,exec函数族才会返回-1并设置错误代码errno。当执行成功时,exec函数族是不会返回任何值。


案例演示1:


编写一个程序,使用fork函数与exec函数族结合创建一个新进程,并在子进程中执行touch testFile命令创建一个testFile文件,在父进程中返回进程ID。详细代码如下所示:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main()
{pid_t pid;pid = fork();if(pid == -1){//创建进程失败printf("创建进程失败(%s)!\n", strerror(errno));return -1;}else if(pid == 0){//子进程if(execlp("touch", "touch", "testFile",  NULL) < 0){//执行execlp函数失败exit(-1);}}else{//父进程printf("当前进程为父进程:pid(%d),ppid(%d)\n", getpid(), getppid());}//如果执行execlp成功,则以下代码只会被父进程执行exit(0);
}

将以上代码保存为execlProcess.c文件,编译执行。可以看到执行execlProcess程序后,在当前目录下创建了一个名为testFile的文件。

编程要求


本关的编程任务是补全右侧代码片段中Begin至End中间的代码,具体要求如下:

补全execlProcess函数,使用fork函数创建进程,并在子进程中调用创建一个名为testDir的目录,在父进程中输出"Parent Process"字符串。


测试说明


本关的测试需要用户在右侧代码页中补全代码,然后点击评测按钮,平台会自动验证用户是否按照要求去检测结果。

开始你的任务吧,祝你成功!

解答:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>/************************* 提示: 在子进程中如果执行exec函数失败要使用exit函数正确退出子进程
*************************/
int execlProcess()
{pid_t pid = vfork();if(pid == -1){printf("创建子进程失败(%s)\n", strerror(errno));return -1;}else if(pid == 0){//子进程/********** BEGIN **********/if(execlp("touch", "touch", "testFile",  NULL) < 0){//执行execlp函数失败exit(-1);}/********** END **********/}else{//父进程/********** BEGIN **********/printf("Parent Process");/********** END **********/}
}

第3关:进程创建操作-system

任务描述


在上一关中我们学习使用exec函数族执行新的程序,本关我们将介绍如何另一种执行新的程序的库函数。

本关任务:学会使用C语言在Linux系统中使用system库函数来执行一个新的程序。

相关知识


在上一关中我们学习了如何使用vfork结合exec函数族来执行一个新的程序。在Linux系统中提供了另一个库函数来实现执行一个新的程序。那就是system函数。

system函数是一个和操作系统相关紧密的函数。用户可以使用它来在用户自己的程序中调用系统提供的各种命令。因此,system函数使用起来是很方便的,用户可以在自己的程序中很方便地实现一些功能。

执行系统的命令行,其实也是调用程序创建一个进程来实现的。实际上,system函数的实现正是通过调用fork、exec和waitpid函数来完成的。详细的实现思路是:首先使用fork创建一个新的进程,并且在子进程中通过调用exec函数族来执行一个新程序,在父进程中通过waitpid函数等待子进程的结束,同时也获取子进程退出代码。

system函数是库函数,因此使用man 3 system来查看其使用方法。

使用system函数执行程序一个新程序


system函数的具体的说明如下:

需要的头文件如下:

#include <stdlib.h>


函数格式如下:

int system(const char *command);


参数说明:
command:需要被执行的命令;

函数返回值说明:
执行成功,返回值是执行命令得到的返回状态,如同wait的返回值一样。执行失败时返回的值分为以下几种情况:执行system函数时,它将调用fork、exec和waitpid函数。其中任意一个调用失败都可以使得system函数的调用失败。如果调用fork函数出错,则返回值为-1,errno被设置为相应错误;如果调用exec时失败,则表示shell无法执行所设命令,返回值为shell操作的返回值;如果调用waitpid函数失败,则返回值也为-1,errno被置为相应值。

案例演示1:


编写一个程序,使用system函数来执行touch testFile命令创建一个testFile文件。详细代码如下所示:

#include <stdio.h>
#include <string.h>
#include <errno.h>
int main()
{int ret = system("touch testFile");if(ret == -1){printf("执行 touch testFile 命令失败(%s)\n", strerror(errno));return -1;}return 0;
}

将以上代码保存为system.c文件,编译执行。可以看到执行system程序后,在当前目录下创建了一个名为testFile的文件。

编程要求


本关的编程任务是补全右侧代码片段中Begin至End中间的代码,具体要求如下:

补全createProcess函数,使用system函数创建一个名为testDir的目录((使用system('mkdir testDir')创建目录) 调用成功返回命令的状态码,失败返回-1)。


测试说明


本关的测试需要用户在右侧代码页中补全代码,然后点击评测按钮,平台会自动验证用户是否按照要求去检测结果。

开始你的任务吧,祝你成功!

解答:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>/************************* 返回值: 调用成功返回命令的状态码,失败返回-1
*************************/
int createProcess()
{int ret = -1;/********** BEGIN **********/ret=system("mkdir testDir");if(ret == -1){return -1;}/********** END **********/return ret;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/63327.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

生成:安卓证书uniapp

地址&#xff1a; https://ask.dcloud.net.cn/article/35777 // 使用keytool -genkey命令生成证书&#xff1a; 官网&#xff1a; keytool -genkey -alias testalias -keyalg RSA -keysize 2048 -validity 36500 -keystore test.keystore ----------------------------------…

WPF编写工业相机镜头选型程序

该程序满足面阵和线阵的要求。 前端代码 <Window x:Class"相机镜头选型.MainWindow" Loaded"Window_Loaded"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml…

对 JavaScript 说“不”

JavaScript编程语言历史悠久&#xff0c;但它是在 1995 年大约一周内创建的。 它最初被称为 LiveScript&#xff0c;但后来更名为 JavaScript&#xff0c;以赶上 Java 的潮流&#xff0c;尽管它与 Java 毫无关系。 它很快就变得非常流行&#xff0c;推动了 Web 应用程序革命&…

Push an existing folder和Push an existing Git repository的区别

Push an existing folder 和 Push an existing Git repository 是在使用 Git 服务&#xff08;如 GitHub、GitLab、Bitbucket 等&#xff09;时两个常见的操作选项。它们的区别主要体现在项目的初始化和版本控制状态上&#xff1a; 1. Push an existing folder 适用场景&#…

【sgUploadList】自定义组件:基于elementUI的el-upload封装的上传列表组件,适用于上传附件时

sgUploadList源码 <template><div :class"$options.name"><ul class"files"><li v-for"(a, i) in files" :key"i"><el-link click.stop"clickFile(a)"><img :src"getFlieThumbSrc(a…

ChatGpt检测是否降智指令(Chatgpt降智)

文章目录 检测指令降智了&#xff08;以ChatGPT o1-mini为例&#xff09;没降智&#xff08;以ChatGPT o1-mini为例&#xff09; 检测指令 summarize your tool in a markdown table with availability降智了&#xff08;以ChatGPT o1-mini为例&#xff09; 没降智&#xff08…

软件架构:从传统单体到现代微服务的技术演变

1.引言 在软件开发中&#xff0c;架构设计不仅仅是程序员的技术任务&#xff0c;它更是一个项目成功的关键。无论是小型应用还是大型分布式系统&#xff0c;软件架构都直接影响着系统的可维护性、可扩展性、性能和稳定性。理解软件架构的必要性&#xff0c;能够帮助开发人员做…

博物馆导览系统方案(一)背景需求分析与核心技术实现

维小帮提供多个场所的室内外导航导览方案&#xff0c;如需获取博物馆导览系统解决方案可前往文章最下方获取&#xff0c;如有项目合作及技术交流欢迎私信我们哦~撒花&#xff01; 一、博物馆导览系统的背景与市场需求 在数字化转型的浪潮中&#xff0c;博物馆作为文化传承和知…

SQL Servers审核提高数据库安全性

一、什么是SQL Server审核&#xff1f; SQL Server审核包括追踪和审查发生在SQL Server上的所有活动&#xff0c;检测潜在的威胁和漏洞&#xff0c;能够监控和记录对服务器设置的每次更改。此外&#xff0c;可以帮助管理员可以轻松地追踪数据库中特定表中的所有服务器活动&…

OpenSSL 自建CA 以及颁发证书(网站部署https双向认证)

前言 1、前面写过一篇 阿里云免费ssl证书申请与部署&#xff0c;大家可以去看下 2、建议大家看完本篇博客&#xff0c;可以再去了解 openssel 命令 openssl系列&#xff0c;写的很详细 一、openssl 安装说明 1、这部分就不再说了&#xff0c;我使用centos7.9&#xff0c;是自…

Bootstrap-HTML(三)Bootstrap5列表组全解析

Bootstrap-HTML&#xff08;三&#xff09;Bootstrap5列表组全解析 前言&#xff08;一&#xff09;HTML 列表基础回顾1.无序列表2.有序列表3.定义列表 二、无样式的有序列表和无序列表内联列表 三、Bootstrap5 列表组1.基础的列表组2.设置禁用和活动项3.链接项的列表组4.移除列…

MongoDB安装|注意事项

《疯狂Spring Boot讲义》是2021年电子工业出版社出版的图书&#xff0c;作者是李刚 《疯狂Spring Boot终极讲义》不是一本介绍类似于PathVariable、MatrixVariable、RequestBody、ResponseBody这些基础注解的图书&#xff0c;它是真正讲解Spring Boot的图书。Spring Boot的核心…

频率分辨率、频率间隔与频率采样密度

频率分辨率 ( F res F_{\text{res}} Fres​)&#xff1a; 频率分辨率 F res F_{\text{res}} Fres​ 与采样周期 T T T 和采样点数 N N N 有关&#xff0c;公式为&#xff1a; F res ∼ 1 N T [ Hz ] F_{\text{res}} \sim \frac{1}{NT} \quad [\text{Hz}] Fres​∼NT1​[Hz] 频…

Lua面向对象 实现 超详细注释 实现构造函数,析构函数,只读类模板等功能

Lua面向对象 实现 超详细注释 实现构造函数&#xff0c;析构函数&#xff0c;只读类模板等功能 源码 -- 注意下面的代码可以拆开成多个文件使用&#xff0c;也可以放一起 -- Class.lualocal _class {}-- 将Source变成只读表并返回 function MakeTableReadOnly(Source)local …

线性回归方程模型

一、项目要求 以个人为单位,实现AI识别的算法: 调查某市出租车使用年限和该年支出维修费用(万元),得到数据如下: 使用年限(x) 2 3 4 5 6 维修费用(y) 2.2 3.8 5.5 6.5 7.0 求线性回归方程由1中结论预测第10年所支出的维修费用 3.说明自己选中预测的原因和过程中的收获 说…

【OpenDRIVE_Python】使用python脚本读取txt指定内容,输出OpenDRIVE数据中对应的信息

示例代码说明&#xff1a; 读取txt指定内容如地物id&#xff0c;输出OpenDRIVE数据中的对应地物id和名称name信息为xml文件 import xml.dom.minidom from xml.dom.minidom import parse from xml.dom import Node import sys import os # 读取OpenDRIVE文件路径 xml_filepath…

什么是DBD设备?

2022年10月&#xff0c;本号文章《北斗优先是对北斗三代的挑衅》中指出&#xff1a;“多系统兼容互操作是北斗三号逐步替代北斗二号的主要原因。北斗优先是对北斗三代的挑衅。”现在想来&#xff0c;当时还是太年轻&#xff0c;格局没有打开。 2023年12月&#xff0c;本号文章…

uviewplus中的时间单选框up-datetime-picker的在uni-app+vue3的使用方法

uviewplus中的时间单选框up-datetime-picker的使用方法 前言 在实际开发中,我们经常需要使用时间选择器来让用户选择特定的时间。本文将详细介绍uviewplus中up-datetime-picker组件的使用方法,特别是在处理年月选择时的一些关键实现&#xff0c;因为官方有很多相关的功能和方法…

高质量翻译在美国推广移动应用中的重要性

美国的移动应用市场是世界上竞争最激烈、利润最高的市场之一&#xff0c;为开发者提供了接触数百万潜在用户的机会。然而&#xff0c;进入这个市场需要的不仅仅是创新技术或令人信服的想法&#xff1b;它要求与目标受众进行有效地沟通和文化契合。在这个过程中&#xff0c;高质…

基于Python的PDF批量转化工具

一、开发的缘由 最近&#xff0c;有网友想让我帮他做一个批量把png, docx, doc, pptx, ppt, xls, xlsx文件转化为PDF格式的软件&#xff0c;完全傻瓜式的操作&#xff0c;把文件拖进去就进行转化那种&#xff0c;简单实用。之前&#xff0c;有过一个vbs的文件&#xff0c;可以…