【Linux C | 进程】创建进程 | vfork函数+exec函数,以及system函数——文中很多C语言例子帮助理解

😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀
🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭
🤣本文内容🤣:🍭介绍 🍭
😎金句分享😎:🍭你不能选择最好的,但最好的会来选择你——泰戈尔🍭

本文未经允许,不得转发!!!

目录

  • 🎄一、vfork 函数概述
    • ✨1.1 vfork 函数介绍
    • ✨1.2 vfork 函数举例
  • 🎄二、exec 函数
    • ✨2.1 execl、execv 函数举例
    • ✨2.2 execlp、execvp 函数举例
    • ✨2.3 execle、execve 函数举例
  • 🎄三、vfork + exec 举例
  • 🎄四、system 函数
  • 🎄五、总结


在这里插入图片描述

🎄一、vfork 函数概述

✨1.1 vfork 函数介绍

函数原型

#include <unistd.h>
pid_t vfork(void);

返回值:父进程返回子进程ID,子进程返回0,出错在父进程返回-1。


vfork 和 fork 函数很像,也是用于创建子进程的,但与fork函数有两点不同:

  • 1、vfork 创建的子进程不复制父进程的任何资源,而是直接占用父进程的资源运行代码。子进程不能从当前函数return或调用exit(),但可以调用_exit()
  • 2、调用 vfork 后,父进程会阻塞,直到子进程终止或调用execcv系列函数。

下表是fork函数和vfork函数的对比:

区别forkvfork
执行两次fork函数之后的代码会执行两次,父进程执行一次,子进程执行一次vfork函数之后的代码会执行两次,父进程执行一次,子进程执行一次
返回两次fork函数返回两次,在父进程返回子进程的进程ID,在子进程返回 0vfork函数返回两次,在父进程返回子进程的进程ID,在子进程返回 0
复制资源fork函数创建的子进程会复制父进程除了代码区之外所有区域(包括数据段、bss段、堆、栈、文件描述符等)vfork 不负责父进程资源
谁先执行调用fork函数后,无法确定是子进程先执行,还是父进程先执行vfork之后,子进程先执行,父进程阻塞直到子进程终止或调用exec系列函数

✨1.2 vfork 函数举例

看例子:
1、即使在子进程sleep(3),子进程依旧先运行,父进程一直阻塞到子进程终止;
2、在子进程中修改变量后,父进程打印的变量全是子进程修改的,说明它们共享资源。

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

int i;		// 存在于程序的bss段
int j=100;	// 存在于程序的数据段
int main()
{
	short s=10; // 存在于栈
	char *str = malloc(20); // 存在于堆
	strcpy(str, "abcdef");
	
    printf("程序开始执行!\n");
	
    pid_t pid = vfork();
	if(pid>0) // 父进程
	{
		printf("父进程执行过程中.... fatherPid=%d, childPid=%d\n", getpid(), pid);
		printf("&i=%p, &j=%p, &s=%p str=%p\n", &i,&j,&s,str);
		printf("i=%d, j=%d, s=%d str=[%s]\n", i,j,s,str);
		i=1;
		j=2;
		s=3;
	}
	else if(pid==0) // 子进程
	{
		sleep(3);
		printf("子进程执行过程中.... fatherPid=%d, childPid=%d\n", getppid(), getpid());
		printf("&i=%p, &j=%p, &s=%p str=%p\n", &i,&j,&s,str);
		printf("i=%d, j=%d, s=%d str=[%s]\n", i,j,s,str);
		
		i=1;
		j=2;
		s=3;
		strcpy(str, "ABCDEF");
		printf("i=%d, j=%d, s=%d str=[%s]\n", i,j,s,str);
		//return(0);  // 执行报错
		//exit(0);
		_exit(0);
	}
	else
	{
		printf("fork error\n");
	}
	free(str);
    while(1)
		sleep(1);
    printf("程序执行结束\n");
    return 0;
}

执行结果:

最后,说明一下,vfork函数一般是结合exec系列函数一起使用的。那什么是exec系列函数呢?


在这里插入图片描述

🎄二、exec 函数

exec系列函数的主要作用:替代原有的进程的代码段、数据段、BSS段、堆区和栈区,然后从新的main开始执行,但是保留了原子进程的PID。

替换的意思就是,调用进程成功执行完exec函数后,原来进程在exec后面的代码都不会被执行了

exec函数原型如下:

#include <unistd.h>
int execl(const char *path, const char *arg, ...);
int execv(const char *path, char *const argv[]);
int execlp(const char *file, const char *arg, ...);
int execvp(const char *file, char *const argv[]);
int execle(const char *path, const char *arg, ..., char * const envp[]);
int execve(const char *path, char *const argv[], char *const envp[]);

这6个函数中,只有execve是系统调用,另外5个是库函数,它们最终都会调用execve

这6个函数怎么记忆、使用:

  • 函数名前4个都是exec
  • 第五个字母:
    • l:是list的意思,要求新程序的每个命令行参数都作为单独的一个函数参数来传递;
      execl("/bin/ls", "ls", "-l", "-a", "./", NULL);
      
    • v:是vector的意思,要求先构造一个指向各个参数的指针数组,再将该数组作为参数传递给execv*
      char *args[]={"ls", "-l", "-a", "./", NULL};
      execv("/bin/ls",args);
      
  • 第六个字母:
    • p:是path的意思,如果参数file包含/,将将其视为路径名;否则从PATH环境变量查找可执行文件;
      execlp("ls", "ls", "-l", "-a", "./", NULL);
      char *args[]={"ls", "-l", "-a", "./", NULL};
      execvp("ls",args);
      
    • e:是environ的意思,可以给新程序传递一个指向环境字符串指针数组的指针。
      char *env_init[] = {"USER=wkd_007", "HOME=/home/wkd", NULL};
      execle("./my_echo", "my_echo", "-l", "-a", "./", NULL, env_init);
      
      char *args[]={"my_echo", "-l", "-a", "./", NULL};
      execve("./my_echo", args, env_init);
      

注意: 使用时,第0个参数也需要传递给exec函数。例如命令ls -l -a ./,则ls是第0个参数。


✨2.1 execl、execv 函数举例

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

#define EXECL_TEST 1
int main()
{
	int i = 10;
#if EXECL_TEST
	printf("EXECL_TEST \n");
    //int res = execl("/bin/ls", "123", "-l", "-a", "./", NULL); // 第0个参数需要传,但exec函数没有使用。
	int res = execl("/bin/ls", "ls", "-l", "-a", "./", NULL);
	if(res == -1)
    {
        perror("execl");
    }
#else
	printf("EXECV_TEST \n");
	char *args[]={"ls", "-l", "-a", "./", NULL};
    int res = execv("/bin/ls",args);
	if(res == -1)
    {
        perror("execl");
    }
#endif
	printf("i=%d\n",i);  // 不会打印,因为exec函数执行成功后,会替换代码段
    
	return 0;
}

✨2.2 execlp、execvp 函数举例

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

#define EXECLP_TEST 0
int main()
{
	int i = 10;
#if EXECLP_TEST
	int res = execl("ls", "ls", "-l", "-a", "./", NULL);
	if(res == -1)
    {
        perror("execl"); // 报错:execl: No such file or directory
    }
	res = execlp("ls", "ls", "-l", "-a", "./", NULL);
	if(res == -1)
    {
        perror("execlp");
    }
#else
	char *args[]={"ls", "-l", "-a", "./", NULL};
    int res = execv("ls",args);
	if(res == -1)
    {
        perror("execv"); // 报错:execv: No such file or directory
    }
	res = execvp("ls",args);
	if(res == -1)
    {
        perror("execvp");
    }
#endif
	printf("i=%d\n",i);  // 不会打印,因为exec函数执行成功后,会替换代码段
    
	return 0;
}

✨2.3 execle、execve 函数举例

程序一:my_echo,用来打印参数列表和环境表。

// gcc my_echo.c -o my_echo
#include <stdio.h>
#include <unistd.h>
extern char** environ;
int main(int argc, char *argv[])
{
	int i=0;
	for(i=0; i<argc; i++)
	{
		printf("argv[%d] = %s\n",i, argv[i]);
	}
	
	for (i = 0; *(environ+i)!=NULL; i++)
	{
		/* echo all command-line args */
		printf ( "environ[%02d]: %s \n", i, *(environ+i) );
	}
    
	return 0;
}

程序二:

#include <stdio.h>
#include <unistd.h>
char *env_init[] = {"USER=wkd_007", "HOME=/home/wkd", NULL};
#define EXECLE_TEST 1
int main()
{
	int i = 10;
#if EXECLE_TEST
	printf("EXECLE_TEST:\n");
	int res = execle("./my_echo", "my_echo", "-l", "-a", "./", NULL, env_init);
	if(res == -1)
    {
        perror("execle");
    }
#else
	printf("EXECVE_TEST:\n");
	char *args[]={"my_echo", "-l", "-a", "./", NULL};
    int res = execve("./my_echo", args, env_init);
	if(res == -1)
    {
        perror("execve");
    }
#endif
	printf("i=%d\n",i);  // 不会打印,因为exec函数执行成功后,会替换代码段
    
	return 0;
}

在这里插入图片描述

🎄三、vfork + exec 举例

int my_system(const char * cmdstring) 
{ 
	pid_t pid; 
	int status; 
	if(cmdstring == NULL) 
	{ 
		return (1); //如果cmdstring为空,返回非零值,一般为1 
	} 
	if((pid = vfork())<0) 
	{ 
	 	status = -1; //fork失败,返回-1 
	} 
	else if(pid == 0) 
	{ 
		execl("/bin/sh", "sh", "-c", cmdstring, (char *)0); 
		_exit(127); // exec执行失败返回127,注意exec只在失败时才返回现在的进程,成功的话现在的进程就不存在啦~~ 
	} 
	else //父进程 
	{ 
		while(waitpid(pid, &status, 0) < 0) 
		{ 
			if(errno != EINTR) 
			{ 
				status = -1; //如果waitpid被信号中断,则返回-1 
				break; 
			} 
		} 
	} 
	return status; //如果waitpid成功,则返回子进程的返回状态 
}

在这里插入图片描述

🎄四、system 函数

函数原型:

#include <stdlib.h>
int system(const char *command);

system函数通过调用/bin/sh -c命令执行command指定的命令,并在命令完成后返回到当前进程。在执行命令期间,SIGCHLD将被阻止,SIGINT和SIGQUIT将被忽略。

因为system在其实现中调用了fork、exec和waitpid,因此有三种返回值:
1、如果fork失败,或者waitpid返回EINTR之外的错误,则system返回-1,且errno中设置了错误类型值;
2、如果exec失败(表示不能执行shell),则其返回值如同shell执行了exit(127)一样。
3、否则所有三个函数(fork、exec和waitpid)都执行成功,并且system的返回值是shell的终止状态,其格式已在waitpid中说明。

使用system而不是直接使用fork和exec的优点是:system进行了所需的各种出错处理,以及各种信号处理。但system执行效率低于exec。

例子:

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

int main()
{
	int res = system("ls -l -a ./");
	if(res == -1)
    {
        perror("system");
    }
	
	return 0;
}

在这里插入图片描述

🎄五、总结

本文先举例介绍了vfork函数,再举例介绍exec系列函数,最后介绍了system函数,文中提供了很多C语言例子帮助理解。

在这里插入图片描述
如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

深入剖析Python最强大图片处理模块——Pillow

目录 一、引言 二、Pillow的功能与特点 三、Pillow的应用场景 四、代码示例 五、Pillow与其他图像处理库的对比 六、结论 一、引言 在Python中&#xff0c;Pillow是用于图像处理的最强大和最流行的库之一。它提供了丰富的功能&#xff0c;使得用户可以轻松地处理、编辑和…

【RT-DETR有效改进】 | 主干篇 | EfficientViT高效的特征提取网络完爆MobileNet系列(轻量化网络结构)

前言 大家好&#xff0c;我是Snu77&#xff0c;这里是RT-DETR有效涨点专栏。 本专栏的内容为根据ultralytics版本的RT-DETR进行改进&#xff0c;内容持续更新&#xff0c;每周更新文章数量3-10篇。 专栏以ResNet18、ResNet50为基础修改版本&#xff0c;同时修改内容也支持Re…

HTTPS基本概念

HTTP 与 HTTPS 有哪些区别&#xff1f; HTTP 是超文本传输协议&#xff0c;信息是明文传输&#xff0c;存在安全风险的问题。HTTPS 则解决 HTTP 不安全的缺陷&#xff0c;在 TCP 和 HTTP 网络层之间加入了 SSL/TLS 安全协议&#xff0c;使得报文能够加密传输。HTTP 连接建立相…

国家急救日倡议活动暨120急救大课堂公益培训在京成功举办

2024年1月20日&#xff0c;由国家卫生健康委员会等多个相关部门指导&#xff0c;中国医院协会急救中心&#xff08;站&#xff09;分会主办&#xff0c;北京急救中心承办的“国家急救日”倡议活动暨急救科普大课堂公益培训系列活动&#xff0c;在全国范围内启动。 健康中国行动…

Kotlin程序设计 扩展篇(一)

Kotlin程序设计&#xff08;扩展一&#xff09; **注意&#xff1a;**开启本视频学习前&#xff0c;需要先完成以下内容的学习&#xff1a; 请先完成《Kotlin程序设计》视频教程。请先完成《JavaSE》视频教程。 Kotlin在设计时考虑到了与Java的互操作性&#xff0c;现有的Ja…

源 “MySQL 5.7 Community Server“ 的 GPG 密钥已安装,但是不适用于此软件包。请检查源的公钥 URL 是否配置正确

Is this ok [y/d/N]: y Downloading packages: 警告&#xff1a;/var/cache/yum/x86_64/7/mysql57-community/packages/mysql-community-server-5.7.44-1.el7.x86_64.rpm: 头V4 RSA/SHA256 Signature, 密钥 ID 3a79bd29: NOKEY 从 file:///etc/pki/rpm-gpg/RPM-GPG-KEY-mysql 检…

加速社区数字化转型:物业app开发的最新趋势

在当今数字化时代&#xff0c;社区数字化转型已经成为业界焦点。特别是在物业管理领域&#xff0c;物业app开发正成为加速社区数字化转型的关键趋势。本文将探讨物业app开发的最新趋势&#xff0c;以及如何通过这些趋势推动社区数字化转型。 物业app开发的关键趋势 随着智能手…

postman测试导入文件

01 上传文件参数 1.选择请求方式 选择post请求方式&#xff0c;输入请求地址 2.填写Headers Key&#xff1a;Content-Type &#xff1b; Value&#xff1a;multipart/form-data 如下图 3.填写body 选择form-data&#xff0c;key选择file类型后value会出现按钮&#xff0…

(十二)Head first design patterns代理模式(c++)

代理模式 代理模式&#xff1a;创建一个proxy对象&#xff0c;并为这个对象提供替身或者占位符以对这个对象进行控制。 典型例子&#xff1a;智能指针... 例子&#xff1a;比如说有一个talk接口&#xff0c;所有的people需要实现talk接口。但有些人有唱歌技能。不能在talk接…

[AutoSar]BSW_OS 06 Autosar OS_Alarms

一、 目录 一、关键词平台说明一、Timer1.1 配置1.2Periodical Interrupt Timer (PIT)和High Resolution Timer (HRT) 二、Alarm 工作机制三、Code3.1创建一个15ms的runnable3.2mapping到basic task3.3生成代码 关键词 嵌入式、C语言、autosar、OS、BSW 平台说明 项目ValueO…

【开源】基于JAVA语言的停车场收费系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 停车位模块2.2 车辆模块2.3 停车收费模块2.4 IC卡模块2.5 IC卡挂失模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 停车场表3.2.2 车辆表3.2.3 停车收费表3.2.4 IC 卡表3.2.5 IC 卡挂失表 四、系统实现五、核心代码…

2024.1.22(150. 逆波兰表达式求值)

2024.1.22(150. 逆波兰表达式求值) 相信看完动画大家应该知道&#xff0c;这和1047. 删除字符串中的所有相邻重复项是差不错的&#xff0c;只不过本题不要相邻元素做消除了&#xff0c;而是做运算&#xff01; // 定义一个Solution类 class Solution { // 定义一个公共方法…

手机上菜谱记录簿在哪 用备忘录放大看菜谱更清晰

作为一个热爱生活的现代人&#xff0c;我深知健康饮食的重要性。然而&#xff0c;每当我想亲手为自己和家人烹饪美食时&#xff0c;厨艺的不精常常让我望而却步。好在互联网时代&#xff0c;网上搜罗的各式菜谱成了我的救星。但问题是&#xff0c;每次做菜时都得反复查找&#…

幻兽帕鲁专用服务器

随着幻兽帕鲁这款游戏的热度持续升温&#xff0c;我们遍寻全网&#xff0c;带给各位玩家一个全新的、高品质的游戏体验——莱卡云服务器。有幻兽帕鲁的热衷者们无需再为了服务器的选取困扰&#xff0c;因为我们可以肯定地说&#xff1a;选择莱卡云&#xff0c;你不会失望。 首先…

尝试着在Stable Diffusion里边使用SadTalker进行数字人制作

首先需要标明的是&#xff0c;我这里是图片说话类型&#xff0c;而且是看了知识星球AI破局俱乐部大航海数字人手册进行操作的。写下这篇文章是防止我以后遗忘。 我使用的基础软件是Stable Diffusion&#xff0c;SadTalker是作为插件放进来的&#xff0c;需要注意的是这对自己的…

用户资源(菜单)控制学习使用

效果图 第一步 需要再定义常量资源 //信访听证 资源前缀public static final String RESPREFIX_MODULE_XINFTZ_"module_xinftz_";//听证专家库public static final ConstantItem RES_MODULE_XINFTZ_TINGZZJK new ConstantItem(RESPREFIX_MODULE_XINFTZ_ "tin…

Drools 规则属性讲解(结合代码实例讲解)

目录 一、规则属性总览 1.1 规则总览 二、具体属性讲解 2.1 enabled属性 2.1.1 代码实现 2.1.1.1 编写规则文件 2.1.1.2 编写规则实体对象 2.1.1.3 编写测试类 2.1.1.4 测试结果 2.2 dialect属性 2.3 salience属性 2.3.1 代码实现 2.3.1.1 编写规则文件 2.3.1.2 编…

超简单的OCR模块:cnocr

前言 毫无疑问的是&#xff0c;关于人工智能方向&#xff0c;python真的十分方便和有效。 这里呢&#xff0c;我将介绍python众多OCR模块中一个比较出色的模块&#xff1a;cnocr 模块介绍 cnocr是一个基于PyTorch的开源OCR库&#xff0c;它提供了一系列功能强大的中文OCR模型和…

网络安全的概述

网络空间的概念 2003年美国提出网络空间的概念&#xff1a;一个由信息基础设施组成的互相依赖的网络。 我国官方文件定义&#xff1a;网络空间为继海&#xff0c;陆&#xff0c;空&#xff0c;天以外的第五大人类活动领域 网络安全发展历史 通信保密阶段 --- 计算机安全阶段…

基于 Spring Boot+MySQL实现的在线考试系统源码+数据库,基于不同类型的客观题,进行自动组卷、批卷等功能的考试系统

1. 部署相关 1.1. 介绍 一个 JAVA 实现的在线考试系统,主要实现一套基于不同类型的客观题,进行自动组卷、批卷等功能的考试系统&#xff08;没有主观题&#xff09; 1.2. 系统架构 后端技术栈基于 Spring Boot数据库MySQLORMMyBatis & MyBatis-plus缓存Redis、guava的L…