Linux系统调用编程

news2025/4/5 18:08:40

文章目录

    • 一、进程和线程
    • 二、Linux的虚拟内存管理和stm32的真实物理内存
      • **Linux虚拟内存管理**
      • STM32物理内存映射
      • 2. 主要区别
    • 三、Linux系统调用函数 fork()、wait()、exec()
      • 1. fork():创建子进程
      • 2. wait():等待子进程状态改变
      • 3. exec():替换进程映像
      • 综合应用
    • 四、总结

一、进程和线程

进程:进程是程序的执行实例,是操作系统分配资源(CPU、内存、文件等)的基本单位。每个进程拥有独立的地址空间和系统资源。一个进程可以有多个线程,比如在Windows系统中,一个运行的xx.exe就是一个进程。
在这里插入图片描述
线程:线程是进程内的执行单元,是CPU调度的基本单位。一个进程可包含多个线程,所有线程共享进程的资源(如内存、文件)。如浏览器的一个标签页可能用一个线程加载页面,另一个线程处理用户输入。
在Linux虚拟机下查看进程
使用命令:ps -a
在这里插入图片描述
终止进程kill 进程号
在这里插入图片描述

二、Linux的虚拟内存管理和stm32的真实物理内存

Linux虚拟内存管理

虚拟地址空间:每个进程拥有独立的虚拟地址空间(通常为4GB或更大),由**内存管理单元(MMU)**动态映射到物理内存或磁盘交换空间。
分页机制:物理内存被划分为固定大小的页(如4KB),虚拟地址通过页表转换到物理页帧。未使用的页可被换出到磁盘(Swap)。

内存保护:不同进程的内存空间隔离,防止非法访问(如写只读页会触发段错误)。

按需分配:内存分配延迟到实际使用时(如malloc申请内存后,物理页在首次访问时才分配)。

共享内存:多个进程可通过虚拟内存映射共享同一物理内存(如动态库)。

STM32物理内存映射

直接访问物理地址:程序直接操作物理内存和外设寄存器,无地址转换层(通常无MMU)。

静态内存布局:内存和外设的地址在芯片设计时固定(如Flash、SRAM、GPIO寄存器的地址在数据手册中定义)。

确定性访问:无分页或交换机制,内存访问延迟固定,适合实时性要求高的场景。

手动管理:开发者需自行规划内存使用(如静态分配或简单动态分配)。

2. 主要区别

特性Linux虚拟内存STM32物理内存映射
地址空间虚拟地址(由MMU转换)直接使用物理地址
硬件支持依赖MMU实现地址转换和保护无MMU,可能支持MPU(仅内存保护)
内存隔离进程间隔离,防止越界访问无隔离,需开发者保证正确性
多任务支持通过虚拟内存实现进程独立地址空间需RTOS配合(如FreeRTOS)或裸机调度
动态内存分配灵活(如malloc+缺页中断)通常静态分配或简单堆管理(易碎片化)
交换空间支持磁盘交换扩展可用内存无交换,受限于物理内存大小
外设访问通过内核驱动(如mmap映射到用户空间)直接读写外设寄存器地址
实时性不确定(因页错误或交换延迟)确定性的低延迟访问

三、Linux系统调用函数 fork()、wait()、exec()

1. fork():创建子进程

功能:复制当前进程,生成一个几乎完全相同的子进程(包括代码、数据、堆栈、文件描述符等)。
子进程从 fork() 的返回处开始执行,与父进程并发运行。
关键特性

返回值含义
>0父进程中返回子进程PID
0子进程中返回0
-1调用失败

写时复制(Copy-On-Write, COW)
父子进程共享物理内存,直到任一进程尝试修改数据时才会复制内存页,提高效率。
示例代码

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

int main() {
    pid_t pid = fork();
    if (pid == -1) {
        perror("fork failed");
        return 1;
    } else if (pid == 0) {
        printf("子进程 (PID: %d)\n", getpid());
    } else {
        printf("父进程 (Child PID: %d)\n", pid);
    }
    return 0;
}

2. wait():等待子进程状态改变

功能
阻塞父进程,直到某个子进程终止或收到信号。
回收子进程资源(避免僵尸进程)。
常用函数
wait(int *status):等待任意子进程结束,状态存入 status。
waitpid(pid_t pid, int *status, int options):
可指定等待的子进程PID(pid=-1 表示任意子进程),支持非阻塞选项(如 WNOHANG)。

状态宏(检查子进程退出原因)
WIFEXITED(status):子进程正常退出。
WEXITSTATUS(status):获取子进程退出码。
WIFSIGNALED(status):子进程被信号终止。
示例代码

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

int main() {
    pid_t pid = fork();
    if (pid == 0) {
        printf("子进程存在...\n");
        _exit(42);  // 子进程退出码42
    } else {
        int status;
        wait(&status);
        if (WIFEXITED(status)) {
            printf("子进程存在码 %d\n", WEXITSTATUS(status));
        }
    }
    return 0;
}

3. exec():替换进程映像

功能
加载新程序到当前进程的内存空间,替换原有代码、数据、堆栈等。
调用成功后,原进程的代码不再执行(除非 exec() 失败)。
常用函数(参数传递方式不同):

函数参数格式示例
execl()可变参数列表(NULL结尾)execl(“/bin/ls”, “ls”, “-l”, NULL)
execv()字符串数组(argv风格)char *args[] = {“ls”, “-l”, NULL}; execv(“/bin/ls”, args)
execvp()自动搜索 PATH 环境变量execvp(“ls”, args)

关键特性
无返回值:成功时不返回,失败时返回 -1(需检查错误)。
保留的文件描述符:默认保持打开(可通过 fcntl 设置 FD_CLOEXEC 关闭)。
示例代码

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

int main() {
    execl("/bin/ls", "ls", "-l", NULL);  // 替换为执行 `ls -l`
    perror("exec 失败");  // 仅当exec失败时执行
    return 1;
}

综合应用

//C程序来说明fork()的用法&
//exec()系统调用以创建进程

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

int main(){
pid_t pid;
int ret = 1;
int status;
pid = fork();

if (pid == -1){

	// pid == -1 表示发生了错误
	printf("can't fork, error occured\n");
	exit(EXIT_FAILURE);
}
else if (pid == 0){

	// pid == 0 表示创建了子进程
	// getpid() 返回调用进程的进程id
	// 返回子进程的进程id
	printf("child process, pid = %u\n",getpid());
	// 返回子进程的父进程,即父进程本身
	printf("parent of child process, pid = %u\n",getppid());

	// argv list第一个参数应该指向
	// 与正在执行的文件关联的文件名
	// 数组指针必须以NULL结尾
	// 指针
	char * argv_list[] = {"ls","-lart","/home",NULL};

	// execv()仅在发生错误时返回。
	// 返回值为-1
	execv("ls",argv_list);
	exit(0);
}
else{
	// 为pid返回一个正数
	// 父进程
	// getppid()返回进程的父进程id
	// 调用进程
        // 返回父进程ID的父进程
	printf("Parent Of parent process, pid = %u\n",getppid());
	printf("parent process, pid = %u\n",getpid());


		// 父进程对子进程调用waitpid()
		// waitpid()系统调用暂停
		// 调用进程直到pid指定的子进程
		// 状态改变
		// 有关所有标志或选项,请参见wait()手册
		if (waitpid(pid, &status, 0) > 0) {

			if (WIFEXITED(status) && !WEXITSTATUS(status))
			printf("program execution successful\n");

			else if (WIFEXITED(status) && WEXITSTATUS(status)) {
				if (WEXITSTATUS(status) == 127) {

					// execv failed
					printf("execv failed\n");
				}
				else
					printf("program terminated normally,"
					" but returned a non-zero status\n");
			}
			else
			printf("program didn't terminate normally\n");
		}
		else {
		// waitpid() failed
		printf("waitpid() failed\n");
		}
	exit(0);
}
return 0;
}

运行效果:
在这里插入图片描述

四、总结

本次学习了进程和线程、虚拟内存管理、系统函数fork()、wait()、exec()的相关知识以及在Linux虚拟机上的基本使用。

参考链接:1.Linux下的fork和exec函数
2.探索 Linux 编程基础 深入理解 fork 函数的实现原理与实践应用
3.详解Linux中的fork,exec,wait
4.添加进程和线程的区别(超详细)

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

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

相关文章

游戏引擎学习第203天

回顾当前情况 在这里我将直播完成整个游戏的制作。我们现在面临一些技术上的困难&#xff0c;确实如此。我的笔记本电脑的电源接口坏了&#xff0c;所以我不得不准备了这台备用笔记本&#xff0c;希望它能够正常工作。我所以希望一切都还好&#xff0c;尽管我不完全确定是否一…

深度学习数据集划分比例多少合适

在机器学习和深度学习中&#xff0c;测试集的划分比例需要根据数据量、任务类型和领域需求灵活调整。 1. 常规划分比例 通用场景 训练集 : 验证集 : 测试集 60% : 20% : 20% 适用于大多数中等规模数据集&#xff08;如数万到数十万样本&#xff09;&#xff0c;平衡了训练数…

CExercise_1_5 水仙花数

题目&#xff1a; 经典循环案例&#xff1a;请求出所有的水仙花数&#xff0c;并统计总共有几个。 所谓的水仙花数是指一个三位数&#xff0c;其各位数字的立方和等于该数本身。 举例&#xff1a;153就是一个水仙花数&#xff0c;153 1 * 1 * 1 5 * 5 * 5 3 * 3 * 3 1 125…

哈密尔顿路径(Hamiltonian Path)及相关算法题目

哈密尔顿路径要求访问图中每个顶点恰好一次&#xff0c;通常用于解决旅行商问题&#xff08;TSP&#xff09;或状态压缩DP问题。 哈密尔顿路径&#xff08;Hamiltonian Path&#xff09;是指在一个图中经过每个顶点恰好一次的路径。如果这条路径的起点和终点相同&#xff08;即…

MINIQMT学习课程Day10

开始获取股票数据课程的学习&#xff1a; 获取qmt账号的持仓情况后&#xff0c;我们进入下一步&#xff0c;如何获得当前账号的委托状况 还是之前的步骤&#xff0c;打开qmt&#xff0c;选择独立交易&#xff0c; 之后使用pycharm&#xff0c;编写py文件 导入包&#xff1a…

JAVA实战开源项目:智慧图书管理系统(Vue+SpringBoot) 附源码

本文项目编号 T 152 &#xff0c;文末自助获取源码 \color{red}{T152&#xff0c;文末自助获取源码} T152&#xff0c;文末自助获取源码 目录 一、系统介绍二、数据库设计三、配套教程3.1 启动教程3.2 讲解视频3.3 二次开发教程 四、功能截图五、文案资料5.1 选题背景5.2 国内…

Linux 系统管理综合实训 —— 基于 NAT 模式的多 IP 配置、Nginx 服务部署及存储管理

1. 虚拟机网络配置&#xff1a;NAT模式与多IP地址设置 将你的虚拟机的网卡模式设置为nat模式&#xff0c;给虚拟机网卡配置三个主机位分别为100、200、168的ip地址 设置静态IP [rootlocalhost ~]# nmcli c modify ens160 ipv4.method manual ipv4.addresses 192.168.2.100/2…

如何在windows 环境、且没有显卡的情况下用python跑通从ModelScope下载的大模型的调用

文章目录 背景介绍源代码&#xff1a;安装调试过程1.设置第三方镜像源2.预先安装&#xff1a;3.在python中创建代码&#xff1a;4.最终修改程序,将device_map从“cuda”改成“auto”&#xff0c;大模型调用1.5B&#xff08;1___5B)的5.最终跑出结果解释&#xff1a;示例&#x…

黑马点评redis改 part 1

本篇将主要阐述短信登录的相关知识&#xff0c;感谢黑马程序员开源&#xff0c;感谢提供初始源文件&#xff08;给到的是实战第7集开始的代码&#xff09;【Redis实战篇】黑马点评学习笔记&#xff08;16万字超详细、Redis实战项目学习必看、欢迎点赞⭐收藏&#xff09;-CSDN博…

【Ragflow】11. 文件解析流程分析/批量解析实现

概述 本文继续对ragflow文档解析部分进行分析&#xff0c;并通过脚本的方式实现对文件的批量上传解析。 文件解析流程 文件解析的请求处理流程大致如下&#xff1a; 1.前端上传文件&#xff0c;通过v1/document/run接口&#xff0c;发起文件解析请求 2.后端api\apps\docum…

第三期:深入理解 Spring Web MVC [特殊字符](数据传参+ 特殊字符处理 + 编码问题解析)

✨前言&#xff1a;传参和状态管理&#xff0c;看似简单其实门道不少 在 Web 开发中&#xff0c;前端和后端最核心的交流方式就是“传参”&#xff0c;而“传参”除了涉及如何写代码获取参数&#xff0c;还藏着很多开发者容易忽略的细节&#xff1a; 为什么 URL 带了中文&…

Everything 安装教程与使用教程(附安装包)

文章目录 前言一、Everything 介绍二、Everything 安装教程1.Everything 安装包下载2.选择安装文件3.选择安装语言4.接受许可协议5.选择安装位置6.配置安装选项7.完成安装 三、Everything 使用教程1.启动软件2.简单关键词搜索3.按类型搜索 前言 在日常使用电脑时&#xff0c;随…

SQL语句(三)—— DQL

目录 基本语法 一、基础查询 1、查询多个字段 2、字段设置别名 3、去除重复记录 4、示例代码 二、条件查询 1、语法 2、条件列表常用的运算符 3、示例代码 三、分组查询 &#xff08;一&#xff09;聚合函数 1、介绍 2、常见的聚合函数 3、语法 4、示例代码 &…

Opencv计算机视觉编程攻略-第九节 描述和匹配兴趣点

一般而言&#xff0c;如果一个物体在一幅图像中被检测到关键点&#xff0c;那么同一个物体在其他图像中也会检测到同一个关键点。图像匹配是关键点的常用功能之一&#xff0c;它的作用包括关联同一场景的两幅图像、检测图像中事物的发生地点等等。 1.局部模板匹配 凭单个像素就…

汇编学习之《push , pop指令》

学习本章前线了解ESP, EBP 指令 汇编学习之《指针寄存器&大小端学习》-CSDN博客 栈的特点&#xff1a; 好比一个垂直容器&#xff0c;可以陆续放入物体&#xff0c;但是先放的物体通常会被后面放的物体压着&#xff0c;只有等上面后放的物品拿出来后&#xff0c;才能…

Python循环控制语句

1. 循环类型概述 Python提供两种主要的循环结构&#xff1a; while循环 - 在条件为真时重复执行for循环 - 遍历序列中的元素 2. while循环 基本语法 while 条件表达式:循环体代码示例 count 0 while count < 5:print(f"这是第{count1}次循环")count 13. f…

微信小程序(下)

目录 在事件处理函数中为 data 中的数据赋值 事件传参 bindinput 的语法格式 实现文本框和 data 之间的数据同步 条件渲染 结合 使用 wx:if hidden wx:if与 hidden 的对比 wx:for 手动指定索引和当前项的变量名 wx:key 的使用 WXSS 和 CSS 的关系 什么是 rpx 尺寸…

【零基础入门unity游戏开发——2D篇】2D 游戏场景地形编辑器——TileMap的使用介绍

考虑到每个人基础可能不一样&#xff0c;且并不是所有人都有同时做2D、3D开发的需求&#xff0c;所以我把 【零基础入门unity游戏开发】 分为成了C#篇、unity通用篇、unity3D篇、unity2D篇。 【C#篇】&#xff1a;主要讲解C#的基础语法&#xff0c;包括变量、数据类型、运算符、…

vector的介绍与代码演示

由于以后我们写OJ题时会经常使用到vector&#xff0c;所以我们必不可缺的是熟悉它的各个接口。来为我们未来作铺垫。 首先&#xff0c;我们了解一下&#xff1a; https://cplusplus.com/reference/vector/ vector的概念&#xff1a; 1. vector是表示可变大小数组的序列容器…