【嵌入式】——Linux系统调用编程
目录
一、进程与线程
1、进程概念
2、线程概念
3、使用进程相关命令
二、使用vi命令
1、使用gcc、make、CMake编译hallo.c
2、使用gcc、make、CMake编译fork.c
三、Linux的“虚拟内存管理”与stm32内存映的区别
1. Linux 虚拟内存管理
2. STM32 物理内存管理
四、树莓派创建用户
总结
一、进程与线程
1、进程概念
定义:
进程是程序的一次执行实例,拥有独立的地址空间、资源(如文件描述符、内存、信号等)和系统状态。每个进程由一个唯一的**进程ID(PID)**标识。
特点:
独立性:进程间相互隔离,一个进程崩溃通常不会直接影响其他进程(通过进程间通信(IPC)机制交互)。
资源开销:创建、销毁或切换进程的开销较大,因为需要分配独立的资源(如内存页表、文件描述符表等)。
地址空间:每个进程拥有独立的虚拟地址空间(通过MMU实现隔离)。
2、线程概念
定义:
线程是进程内的执行单元,共享同一进程的地址空间和资源(如内存、文件描述符等),但拥有独立的栈、寄存器状态和程序计数器(PC)。
特点:
轻量级:创建、切换线程的开销远小于进程,因为无需分配新的地址空间。
共享资源:线程间可直接访问同一进程的全局变量、堆内存等,但也需要同步机制(如互斥锁)避免竞争。
协作性:一个线程崩溃可能导致整个进程崩溃(因为共享地址空间)。
3、使用进程相关命令
(1)在home目录下创建一个子目录
mkdir ~/homework
ps -a
kill 3273562
二、使用vi命令
1、使用gcc、make、CMake编译hallo.c
(1)gcc编译
vi hello.c
#include <unistd.h>
int main() {
write(1, "Hello, linux!\n", 23);
return 0;
}
(2)make
vi Makefile
编写 Makefile
CC = gcc
CFLAGS = -Wall
TARGET = hello
SRC = hello.c
all: $(TARGET)
$(TARGET): $(SRC)
$(CC) $(CFLAGS) -o $@ $^
clean:
rm -f $(TARGET)
编译
make # 编译
./hello # 运行
(3)CMake
编写 hello.c(同上),确保 hello.c 内容不变。
编写 CMakeLists.txt
vi CMakeLists.txt
文件写入以下内容:
cmake_minimum_required(VERSION 3.10)
project(hello)
set(CMAKE_C_FLAGS "-Wall")
add_executable(hello hello.c)
编译及运行
mkdir build && cd build
cmake .. # 生成 Makefile
make # 编译
./hello # 运行
2、使用gcc、make、CMake编译fork.c
fork.c
#include <stdio.h>
//#include <sys[表情]pes.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;
}
(1)gcc
同前面编译过程一样,只需要换下文件内容即可
(2)make
更改Makefile ,其余过程一样
CC = gcc
CFLAGS = -Wall
TARGET = fork
SRC = fork.c
all: $(TARGET)
$(TARGET): $(SRC)
$(CC) $(CFLAGS) -o $@ $^
clean:
rm -f $(TARGET)
创建 CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(fork)
set(CMAKE_C_FLAGS "-Wall -Wextra") # 启用警告
add_executable(fork fork.c) # 生成可执行文件
编译和运行
mkdir build && cd build
cmake .. # 生成 Makefile
make # 编译
./fork # 运行
三、Linux的“虚拟内存管理”与stm32内存映的区别
1. Linux 虚拟内存管理
核心机制
地址空间虚拟化:
每个进程拥有独立的 虚拟地址空间(32位系统通常为4GB,64位系统更大),与物理内存分离。
通过 MMU(内存管理单元) 和 页表 动态映射到物理内存或磁盘(Swap)。
关键功能:
分页(Paging):内存按固定大小(如4KB)分页,物理内存和虚拟页通过页表关联。
按需加载:程序启动时仅加载必要页,其他页在访问时触发 缺页异常,由内核动态加载。
内存保护:不同进程的地址空间隔离,防止非法访问(如写只读页会触发段错误)。
Swap 机制:将不活跃的页换出到磁盘,扩展可用内存。
优势
多进程隔离:进程无法直接访问其他进程或内核的内存。
大地址空间:程序可使用的内存远超物理内存大小。
内存共享:动态库、文件映射(mmap)等可被多个进程共享。
2. STM32 物理内存管理
核心机制
直接物理内存访问
程序直接操作 物理地址(无虚拟地址层),通常通过 内存映射(Memory Map) 访问外设寄存器或静态分配的RAM。
典型场景:
外设寄存器映射到固定地址(如 0x40000000)。
静态分配的全局变量位于链接脚本定义的RAM区域。
关键特点:
无内存隔离:所有代码共享同一物理地址空间,需开发者自行保证安全性。
确定性访问:无分页/缺页机制,访问延迟固定。
无 Swap:仅使用片上RAM或外部扩展RAM,无法利用磁盘。
四、树莓派创建用户
为了使其它人也能够连接树莓派,我们需要创建他们的用户并赋予权限
1、切换到Root用户
sudo -i
2、创建新用户
useradd -m 新用户名
3、设置密码
passwd 新用户名
4、将新用户加入到sudo用户组
adduser newname sudo
5、拷贝数据
cp -R /home/旧用户名/* /home/新用户名/
6、查看用户所属组
id 新用户名
7、更改文件所属
sudo chown 新用户名:所属组(group) /home/新用户名/*
8、修改shell为bin/bash
usermod -s /bin/bash arslantech
创建用户完成
总结
对linux的vi命令有了更深入的了解,同时学习到了多种编译方式,初步接触make和CMake编译方式,可能存在部分错误。