
在嵌入式 Linux 系统中,进程是正在执行的程序实例。每个进程都有自己独立的地址空间、系统资源(如文件描述符、信号处理等)。进程由内核进行调度和管理,是系统资源分配的基本单位。
在操作系统中,进程(Process) 是计算机中正在执行的程序的实例,是操作系统进行资源分配和调度的基本单位。
程序 | 进程 |
|---|---|
静态的代码文件(如 a.out) | 动态的执行实体 |
存储在磁盘中 | 驻留在内存中 |
无生命周期概念 | 有明确的创建、运行、终止过程 |
不占用系统资源 | 占用CPU、内存等资源 |
malloc)。
每个进程都有一个唯一的标识符,即进程 ID(PID)。PID 是一个非负整数,内核使用 PID 来标识和管理进程。在 Linux 系统中,init进程的 PID 始终为 1,它是所有其他进程的祖先。
进程在其生命周期内会处于不同的状态,常见的有:
SIGCHLD 信号处理或显式调用 waitpid)。
# 查看系统中所有进程
ps aux
# 实时监控进程资源占用
top
# 跟踪进程的系统调用
strace -p <PID>
# 终止进程
kill -9 <PID>在嵌入式Linux数据采集系统中:
fork() 创建子进程。
exec() 执行传感器数据采集程序。
fork()函数在嵌入式 Linux 应用开发中,最常用的创建新进程的方法是使用 fork() 函数。fork() 函数会创建一个与父进程几乎完全相同的子进程。子进程会复制父进程的地址空间、文件描述符等资源。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
pid_t pid;
// 创建子进程
pid = fork();
if (pid < 0) {
perror("fork failed");
exit(EXIT_FAILURE);
} else if (pid == 0) {
// 子进程代码
printf("This is the child process. PID: %d\n", getpid());
exit(EXIT_SUCCESS);
} else {
// 父进程代码
printf("This is the parent process. Child PID: %d\n", pid);
}
return 0;
}fork() 函数返回两次,一次在父进程中,返回子进程的 PID;另一次在子进程中,返回 0。fork() 的返回值,可以区分父进程和子进程,并在不同的分支中编写各自的代码逻辑。 exit()函数进程可以通过调用 exit() 函数来终止自身。exit() 函数会清理进程占用的资源,并向父进程返回一个状态码。父进程可以通过 wait() 或 waitpid() 函数获取子进程的退出状态。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main() {
pid_t pid;
int status;
pid = fork();
if (pid < 0) {
perror("fork failed");
exit(EXIT_FAILURE);
} else if (pid == 0) {
// 子进程代码
printf("Child process is exiting with status 42\n");
exit(42);
} else {
// 父进程等待子进程结束
wait(&status);
if (WIFEXITED(status)) {
printf("Parent process: Child exited with status %d\n", WEXITSTATUS(status));
}
}
return 0;
}exit(42) 终止,并返回状态码 42。wait(&status) 等待子进程结束,并使用 WIFEXITED(status) 和 WEXITSTATUS(status) 宏来检查子进程是否正常退出以及获取其退出状态码。 管道是一种简单的进程间通信机制,它允许一个进程将数据发送到另一个进程。管道分为匿名管道和命名管道。
匿名管道只能用于具有亲缘关系(如父子进程)的进程之间通信。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define BUFFER_SIZE 1024
int main() {
int pipefd[2];
pid_t pid;
char buffer[BUFFER_SIZE];
// 创建管道
if (pipe(pipefd) == -1) {
perror("pipe failed");
exit(EXIT_FAILURE);
}
pid = fork();
if (pid < 0) {
perror("fork failed");
close(pipefd[0]);
close(pipefd[1]);
exit(EXIT_FAILURE);
} else if (pid == 0) {
// 子进程关闭读端
close(pipefd[0]);
// 向管道写入数据
const char *message = "Hello from child process";
write(pipefd[1], message, strlen(message));
// 关闭写端
close(pipefd[1]);
} else {
// 父进程关闭写端
close(pipefd[1]);
// 从管道读取数据
ssize_t bytes_read = read(pipefd[0], buffer, sizeof(buffer) - 1);
if (bytes_read > 0) {
buffer[bytes_read] = '\0';
printf("Parent process received: %s\n", buffer);
}
// 关闭读端
close(pipefd[0]);
}
return 0;
}pipe(pipefd) 创建一个匿名管道,pipefd[0] 用于读,pipefd[1] 用于写。pipefd[0],向管道写入数据后关闭写端 pipefd[1]。pipefd[1],从管道读取数据后关闭读端 pipefd[0]。 命名管道可以用于不具有亲缘关系的进程之间通信。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <string.h>
#define FIFO_NAME "my_fifo"
#define BUFFER_SIZE 1024
int main() {
int fd;
char buffer[BUFFER_SIZE];
// 创建命名管道
if (mkfifo(FIFO_NAME, 0666) == -1) {
perror("mkfifo failed");
exit(EXIT_FAILURE);
}
// 打开命名管道进行读取
fd = open(FIFO_NAME, O_RDONLY);
if (fd == -1) {
perror("open failed");
unlink(FIFO_NAME);
exit(EXIT_FAILURE);
}
// 从命名管道读取数据
ssize_t bytes_read = read(fd, buffer, sizeof(buffer) - 1);
if (bytes_read > 0) {
buffer[bytes_read] = '\0';
printf("Received: %s\n", buffer);
}
// 关闭文件描述符并删除命名管道
close(fd);
unlink(FIFO_NAME);
return 0;
}mkfifo(FIFO_NAME, 0666) 创建一个名为 my_fifo 的命名管道。open(FIFO_NAME, O_RDONLY) 打开命名管道进行读取。unlink(FIFO_NAME) 删除命名管道。信号是一种异步通知机制,用于向进程发送事件消息。常见的信号有 SIGTERM(终止进程)、SIGINT(由用户通过 Ctrl + C 产生)等。
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void signal_handler(int signum) {
printf("Received signal %d. Exiting...\n", signum);
exit(EXIT_SUCCESS);
}
int main() {
// 注册信号处理函数
if (signal(SIGINT, signal_handler) == SIG_ERR) {
perror("signal registration failed");
exit(EXIT_FAILURE);
}
printf("Press Ctrl + C to send SIGINT signal...\n");
while (1) {
sleep(1);
}
return 0;
}signal(SIGINT, signal_handler) 注册一个信号处理函数 signal_handler,用于处理 SIGINT 信号。Ctrl + C 时,进程会收到 SIGINT 信号,调用 signal_handler 函数,然后终止进程。 假设我们要开发一个简单的监控系统,用于监控某个特定进程的运行状态。如果该进程异常退出,我们的监控程序将重新启动它。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <signal.h>
#include <string.h>
#define MONITORED_PROGRAM "./target_program"
void restart_monitored_process() {
pid_t pid = fork();
if (pid < 0) {
perror("fork failed");
exit(EXIT_FAILURE);
} else if (pid == 0) {
// 子进程执行被监控的程序
execl(MONITORED_PROGRAM, MONITORED_PROGRAM, NULL);
perror("execl failed");
exit(EXIT_FAILURE);
}
}
void signal_handler(int signum) {
if (signum == SIGCHLD) {
int status;
pid_t pid;
// 等待子进程结束
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
if (WIFEXITED(status)) {
printf("Monitored process exited with status %d. Restarting...\n", WEXITSTATUS(status));
restart_monitored_process();
}
}
}
}
int main() {
// 启动被监控的进程
restart_monitored_process();
// 注册信号处理函数
if (signal(SIGCHLD, signal_handler) == SIG_ERR) {
perror("signal registration failed");
exit(EXIT_FAILURE);
}
while (1) {
sleep(1);
}
return 0;
}restart_monitored_process 函数用于启动被监控的程序。signal_handler 函数处理 SIGCHLD 信号,当被监控的子进程退出时,它会重新启动该进程。main 函数中,首先启动被监控的进程,然后注册 SIGCHLD 信号处理函数,最后进入一个无限循环,使监控程序持续运行。综上所述,在嵌入式Linux系统中,进程是系统资源分配和调度的基本单位。每个进程都有自己的地址空间和系统资源,通过进程间的通信和同步机制,可以实现不同进程间的数据交换和协作。进程管理对于嵌入式系统的性能和稳定性至关重要。
[1] 汪明虎,欧文盛。嵌入式 Linux 开发 - 基于 ARM [M]. 人民邮电出版社,2006. [2] 嵌入式 Linux 系统开发:从零基础到实战经验,一步步揭秘 [EB/OL]. [发布时间 2024-03-20]. 嵌入式Linux系统开发:从零基础到实战经验,一步步揭秘-LINUX-PHP中文网. 介绍了嵌入式 Linux 系统开发从基础认知到实战的各个环节,其中关于进程监控等 Linux 基础概念部分,对理解嵌入式 Linux 进程相关知识有一定辅助作用。 [3] 嵌入式软件设计入门:Linux 简介与实战示例 [EB/OL]. [发布时间 2024-12-01]. 嵌入式软件设计入门:Linux简介与实战示例. 文中对 Linux 在嵌入式系统中的应用进行了介绍,虽然未专门针对进程实战开发,但 Linux 在嵌入式系统中的特性与应用场景等内容,有助于从宏观角度理解进程开发所处的环境。 [4] 【嵌入式 Linux (基础篇)】嵌入式 Linux 底层系统开发流程和应用开发流程 [EB/OL]. [发布时间 2024-10-24]. 【嵌入式Linux(基础篇)】嵌入式Linux底层系统开发流程和应用开发流程_嵌入式linux uboot kernel 和根文件系统开发过程-CSDN博客. 详细阐述了嵌入式 Linux 底层系统开发流程和应用开发流程,进程开发作为应用开发的一部分,该流程介绍有助于明确进程实战开发在整个嵌入式 Linux 开发体系中的位置和作用。 [5] 嵌入式系统文献综述 [EB/OL].. 嵌入式系统文献综述 - 道客巴巴. 该文献综述介绍了嵌入式系统的相关背景及实验教学系统等内容,对了解嵌入式系统整体发展背景以及相关硬件平台等知识有帮助,而硬件平台是进程实战开发的基础支撑。 [6] 嵌入式软件工程师学习路线与书籍推荐! [发布时间 2023-07-18]. 推荐了嵌入式学习书籍,并对嵌入式 Linux 高级程序设计中进程相关概念、进程间通信等内容的学习提供了指导,为深入学习进程实战开发提供了学习资源参考 。