【XTerminal】【树莓派】Linux系统下的函数调用编程

news2025/4/10 10:39:12

目录

一、XTerminal下的Linux系统调用编程

1.1理解进程和线程的概念并在Linux系统下完成相应操作

(1) 进程

(2)线程

(3) 进程 vs 线程

(4)Linux 下的实践操作

1.2Linux的“虚拟内存管理”和stm32正式物理内存(内存映射)的区别

(1)Linux虚拟内存管理

(2)STM32物理内存映射

(3)主要区别

1.3理解 Linux系统调用函数 fork()、wait()、exec() 等并通过vi 编辑一个c程序

(1)系统调用函数介绍

fork()

wait()

exec()

(2)创建syscall_demo.c

(3)编写示例程序

(4)编译运行

二、在树莓派中创建多个账号并完成Linux系统调用函数联系

1.1组员账号创建

1.2在树莓派环境中学习并调用fork()、wait()和exec()函数

(1)创建文件 syscall_demo.c

(2)编写示例程序

(3)编译运行


一、XTerminal下的Linux系统调用编程

1.1理解进程和线程的概念并在Linux系统下完成相应操作

(1) 进程

定义:进程是程序的一次执行实例,拥有独立的内存空间、文件描述符和系统资源。

特点:

  • 每个进程有唯一的 PID(进程ID)。

  • 进程间相互隔离,通信需通过 IPC(进程间通信) 机制(如管道、共享内存等)。

  • 创建进程通过 fork()exec() 系统调用。

(2)线程

定义:线程是进程内的执行单元,共享同一进程的内存和资源。

特点:

  • 线程有独立的 栈,但共享堆、全局变量和文件描述符。

  • 创建线程通过 pthread_create()(POSIX 线程库)。

  • 轻量级,切换开销比进程小。

(3) 进程 vs 线程

特性进程线程
独立性完全隔离共享同一进程资源
创建开销大(需复制内存)小(共享内存)
通信方式IPC(管道、信号等)直接读写共享变量
崩溃影响不影响其他进程导致整个进程终止

(4)Linux 下的实践操作

ps -a

通过kill命令尝试终止该进程

kill -9 PID

我们发现提示没有那个进程。这是因为该进程为临时进程,执行完毕后已自动退出,因此报错 。

我们可以通过下面命令查找系统中所有的进程及其对应的PID

ps -aux

我们可以对应选择一个进程进行结束

1.2Linux的“虚拟内存管理”和stm32正式物理内存(内存映射)的区别

(1)Linux虚拟内存管理

核心机制: Linux通过虚拟内存抽象物理内存,为每个进程提供独立的、连续的虚拟地址空间(通常为4GB,32位系统),由MMU(内存管理单元)动态映射到物理内存或磁盘交换空间。

其工作流程为:

进程访问虚拟地址 → MMU查页表 → 若页在物理内存则访问,否则触发缺页异常 → 内核加载缺失页或终止进程

(2)STM32物理内存映射

核心机制: STM32等嵌入式MCU通常直接操作物理内存,通过内存映射(将外设寄存器、Flash、RAM等硬件资源分配到固定的物理地址。

其典型内存布局为:

0x00000000 - 0x1FFFFFFF: Flash(代码存储) 0x20000000 - 0x2001FFFF: SRAM(数据) 0x40000000 - 0x5FFFFFFF: 外设寄存器

(3)主要区别

特性Linux虚拟内存STM32物理内存映射
地址空间虚拟地址(进程独立)物理地址(全局唯一)
硬件支持依赖MMU实现地址转换无MMU,直接访问物理地址
内存扩展支持Swap扩展虚拟内存仅限芯片内置的物理内存
内存保护通过页表实现权限控制无保护,需开发者谨慎操作
外设访问通过/dev/mem或驱动间接访问直接读写内存映射的外设寄存器
使用场景通用计算(多任务、复杂应用)实时嵌入式系统(确定性、低延迟)

存在差异的原因:

Linux需要支持多进程、大内存应用,虚拟内存提供灵活性和安全性。

STM32:追求实时性和确定性,省去MMU降低开销,适合裸机或RTOS(如FreeRTOS)。

1.3理解 Linux系统调用函数 fork()、wait()、exec() 等并通过vi 编辑一个c程序

(1)系统调用函数介绍

fork()

功能:创建一个新的进程(子进程),子进程是父进程的副本。

返回值:

  • 父进程中返回子进程的PID(>0)。

  • 子进程中返回0。

  • 失败时返回-1。

头文件:<unistd.h>

wait()

功能:父进程等待子进程结束,并回收子进程的资源(防止僵尸进程)。

参数:int *status(存储子进程的退出状态)。

返回值:成功时返回子进程PID,失败时返回-1。

头文件:<sys/wait.h>

exec()

功能:替换当前进程的映像为新的程序(如运行另一个可执行文件)。

常用变体:

  • execl():参数列表形式。

  • execv():参数数组形式。

  • execvp():自动搜索PATH环境变量。

返回值:成功时不返回,失败时返回-1。

头文件:<unistd.h>

(2)创建syscall_demo.c

vi syscall_demo.c

(3)编写示例程序

进入vi编译器后,按"i"进入插入模式

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

int main() {
    pid_t pid;
    int status;

    pid = fork();

    if (pid < 0) {
        fprintf(stderr, "Fork failed!\n");
        return 1;
    } else if (pid == 0) {
        printf("Child Process (PID=%d): Hello from fork()!\n", getpid());
        execlp("ls", "ls", "-l", NULL);
        perror("exec failed");
        return 1;
    } else {
        printf("Parent Process (PID=%d): Waiting for child...\n", getpid());
        wait(&status);
        printf("Parent: Child exited with status %d\n", WEXITSTATUS(status));
    }

    return 0;
}

编写完成后按Esc退出插入模式,输入“:wq”保存并退出

注:

保存文件Esc:w → 回车保存但不退出
保存并退出Esc:wq → 回车保存并退出
强制退出不保存Esc:q! → 回车丢弃所有修改

(4)编译运行

输入下面代码进行编译运行:

#编译
gcc syscall_demo.c -o syscall_demo
#添加权限
chmod +x syscall_demo
# 运行
./syscall_demo

结果解释:

Parent Process (PID=960685): Waiting for child
#父进程(PID=960685)打印信息,表示已通过 fork() 创建子进程,并调用 wait() 进入阻塞状态,等待子进程结束。

Child Process (PID=960686): Hello from fork()!
#子进程(PID=960686)被创建后,打印自己的 PID 和消息,随后调用execlp("ls", "ls", "-l", NULL)。
子进程的代码映像被替换为 ls -l 命令,原程序的后续代码(如 perror)不再执行。

-rwxr-xr-x 1 zhangzy group2 17056 Apr  3 23:23 a.out
-rwxr-xr-x 1 zhangzy group2 17056 Apr  3 23:25 syscall_demo
-rw-r--r-- 1 zhangzy group2   610 Apr  3 23:23 syscall_demo.c
-rwxr-xr-x 1 zhangzy group2    65 Apr  3 22:12 test.sh
#ls -l 命令的输出,显示当前目录下的文件详情:
总用量 48

Parent: Child exited with status 
#子进程(ls -l)执行完毕后,父进程的 wait(&status) 返回。
WEXITSTATUS(status) 提取子进程的退出状态码 0,表示 ls 命令成功执行。

二、在树莓派中创建多个账号并完成Linux系统调用函数联系

1.1组员账号创建

首先要进行树莓派的VNC远程登录,具体步骤可以看我前面的博客:树莓派3b:环境配置,VNC远程控制并进行简单代码运行_树莓派vnc-CSDN博客

先进入VNC命令行

(1)创建用户

为每个组员创建一个独立的系统账号,并生成各自的目录

sudo adduser user1
sudo adduser user2

(2)配置用户权限

确保用户有基本的开发权限,(如sudo权限)

# 将用户添加到sudo组(允许执行管理员命令)
sudo usermod -aG sudo username1

# 验证用户组
groups username1

我们通过命令行测试,发现新用户可以进行登录(后续代码也可以通过电脑命令行实现)

1.2在树莓派环境中学习并调用fork()、wait()和exec()函数

(1)创建文件 syscall_demo.c

nano syscall_demo.c

(2)编写示例程序

该程序展示了Linux系统调用fork()、exec()、和wait()函数的工作过程

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

int main() {
    pid_t pid;
    int status;

    // 1. fork() 示例
    pid = fork();

    if (pid < 0) {
        fprintf(stderr, "Fork failed!\n");
        return 1;
    } else if (pid == 0) {
        // 子进程
        printf("Child Process (PID=%d): Hello from fork()!\n", getpid());
        
        // 2. exec() 示例:替换为执行 'ls' 命令
        execlp("ls", "ls", "-l", NULL);
        
        // 如果exec失败,才会执行到这里
        perror("exec failed");
        return 1;
    } else {
        // 父进程
        printf("Parent Process (PID=%d): Waiting for child...\n", getpid());
        
        // 3. wait() 示例
        wait(&status);
        printf("Parent: Child exited with status %d\n", WEXITSTATUS(status));
    }

    return 0;
}

(3)编译运行

编译:

gcc syscall_demo.c -o syscall_demo

运行:

./syscall_demo

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

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

相关文章

umi框架开发移动端h5

1、官网&#xff1a;https://umijs.org/ 2、创建出来的项目 yarn create umi yarn start3、推荐目录结构 . ├── config │ └── config.ts ├── public//静态资源 ├── dist ├── mock │ └── app.ts&#xff5c;tsx ├── src │ ├── .umi │ ├── .um…

3.9/Q2,Charls最新文章解读

文章题目&#xff1a;Association between remnant cholesterol and depression in middle-aged and older Chinese adults: a population-based cohort study DOI&#xff1a;10.3389/fendo.2025.1456370 中文标题&#xff1a;中国中老年人残留胆固醇与抑郁症的关系&#xff1…

Java Lambda 表达式提升效率

lambda 表达式的应用场景 Stream 的应用场景 Lambda/Stream 的进一步封装 自定义函数式接口&#xff08;用 jdk 自带的函数式接口也可以&#xff09; https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html import java.io.Serializable;/*** 可序…

人工智能混合编程实践:C++ ONNX进行图像超分重建

人工智能混合编程实践:C++ ONNX进行图像超分重建 前言相关介绍C++简介ONNX简介ONNX Runtime 简介**核心特点**图像超分辨率重建简介应用场景前提条件实验环境项目结构使用C++ ONNX进行图像超分重建sr_main.cpp参考文献前言 由于本人水平有限,难免出现错漏,敬请批评改正。更多…

K8S学习之基础七十四:部署在线书店bookinfo

部署在线书店bookinfo 在线书店-bookinfo 该应用由四个单独的微服务构成&#xff0c;这个应用模仿在线书店的一个分类&#xff0c;显示一本书的信息&#xff0c;页面上会显示一本书的描述&#xff0c;书籍的细节&#xff08;ISBN、页数等&#xff09;&#xff0c;以及关于这本…

Python不可变数据类型全解析:原理、优势与实战指南

目录 引言&#xff1a;为什么Python要区分可变与不可变&#xff1f; 一、不可变数据类型的核心特性 二、五大不可变数据类型深度解析 三、不可变数据类型的三大核心优势 四、不可变数据类型的典型应用场景 五、不可变 vs 可变&#xff1a;如何选择&#xff1f; 六、实战技…

Apache Doris 2025 Roadmap:构建 GenAI 时代实时高效统一的数据底座

在全球 290 位开发者的协作下&#xff0c;Apache Doris 在 2024 年完成了 7000 次代码提交&#xff0c;并发布了 22 个版本&#xff0c;实现在实时分析、湖仓一体和半结构化数据分析等核心场景的技术突破及创新。 2025 年&#xff0c;Apache Doris 社区将秉承“以场景驱动创新…

二极管正负极区分

二极管正负极区分 二极管是一种具有单向导电性的半导体器件&#xff0c;正确区分正负极对于其使用非常重要。以下是几种常见的二极管正负极区分方法&#xff1a; 1. 外观标识 有标记的二极管 色环或色点&#xff1a;许多二极管在表面会有一个色环或色点&#xff0c;这个标记…

【c++深入系列】:类与对象详解(中)

&#x1f525; 本文专栏&#xff1a;c &#x1f338;作者主页&#xff1a;努力努力再努力wz &#x1f4aa; 今日博客励志语录&#xff1a; 不是因为看到希望才坚持&#xff0c;而是坚持了才能看到希望 那么上一篇博客我讲解了什么是类和对象以及类和对象是怎么定义的&#xff0…

汽车 HMI 设计的发展趋势与设计要点

一、汽车HMI设计的发展历程与现状 汽车人机交互界面&#xff08;HMI&#xff09;设计经历了从简单到复杂、从单一到多元的演变过程。2012年以前&#xff0c;汽车HMI主要依赖物理按键进行操作&#xff0c;交互方式较为单一。随着特斯拉Model S的推出&#xff0c;触控屏逐渐成为…

《AI大模型应知应会100篇》第56篇:LangChain快速入门与应用示例

第56篇&#xff1a;LangChain快速入门与应用示例 前言 最近最火的肯定非Manus和OpenManus莫属&#xff0c;因为与传统AI工具仅提供信息不同&#xff0c;Manus能完成端到端的任务闭环。例如用户发送“筛选本月抖音爆款视频”&#xff0c;它会自动完成&#xff1a; 爬取平台数据…

Java 大视界 -- Java 大数据在智能农业无人机植保作业路径规划与药效评估中的应用(165)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…

哈希表系列一>两数之和

目录 题目&#xff1a;方法&#xff1a;暴力代码&#xff1a;优化后代码&#xff1a; 题目&#xff1a; 链接: link 方法&#xff1a; 暴力代码&#xff1a; public int[] twoSum(int[] nums, int target) {解法一&#xff1a;暴力解法&#xff1a;int n nums.length;for(int…

CAD插件实现:自动递增编号(前缀、后缀、位数等)——CADc#实现

cad中大量输入一定格式的递增编号时&#xff0c;可用插件实现&#xff0c;效果如下&#xff1a; ①本插件可指定数字位数、起始号码、加前缀、后缀、文字颜色等&#xff08;字体样式和文字所在图层为cad当前图层和当前字体样式&#xff09;。 ②插件采用Jig方式&#xff0c;即…

C语言--回文字符串

输入&#xff1a;字符串&#xff0c;判断是否是回文字符串&#xff0c;例如abcba输出Yes 输出&#xff1a;是否 代码 思路&#xff1a;使用两个指针分别指向头和尾&#xff0c;依次对比第一个元素和最后一个元素&#xff0c;第二个和倒数第二个元素&#xff0c;如果遇到不相同…

Coco-AI 支持嵌入,让你的网站拥有 AI 搜索力

在之前的实践中&#xff0c;我们已经成功地把 Hexo、Hugo 等静态博客和 Coco-AI 检索系统打通了&#xff1a;只要完成向量化索引&#xff0c;就可以通过客户端问答界面实现基于内容的智能检索。 这一层已经很好用了&#xff0c;但总觉得少了点什么—— 比如用户还得专门打开一…

TRDI 公司的RiverPro 和 RioPro ADCP 用户指南

TRDI 公司 RiverPro 和 RioPro ADCP 用户指南 简介第一章 - 概述第二章 - 安装第三章 - 采集数据第四章 - 维护第五章 - 测试RIVERPRO/RIOPRO第六章 - 故障排除第七章 - 将系统返回TRDI进行维修第八章 - 规格第九章 - 命令第十章 - 输出数据格式附录A-合规通知首次完整翻译《Ri…

OpenCV 图形API(11)对图像进行掩码操作的函数mask()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 描述 对矩阵应用掩码。 该函数mask设置来自给定矩阵的值&#xff0c;如果掩码矩阵中对应的像素值设为true&#xff0c;否则将矩阵的值设为0。 支持的源矩阵…

使用C#写的一个Kafka的使用工具

由于offset不支持通过界面推送数据&#xff0c;所以我写了一个kafka的连接工具&#xff0c;能够直接从界面推送数据&#xff0c;方便使用。由于使用的是C#写的&#xff0c;所以比offset要流畅的多。 1、数据源连接 2、获取集群的topic 3、点击获取数据能够获取最新的100条数…

【通知】STM32MP157驱动开发课程全新升级!零基础入门嵌入式Linux驱动,掌握底层开发核心技能!

在嵌入式Linux系统开发中&#xff0c;驱动程序开发是一项关键技术&#xff0c;它作为硬件与软件之间的桥梁&#xff0c;实现了操作系统对硬件设备的控制。相较于嵌入式Linux应用开发&#xff0c;驱动开发由于涉及底层硬件且抽象程度较高&#xff0c;往往让初学者感到难度较大。…