系统操作 - 线程/进程操作
1.1. 多线程概述
进程和线程的概念是操作系统(OS)与普通微控制器之间最大的区别之一。在多任务系统中,可以划分系统资源,使不同任务独立运行。从宏观角度来看,多个应用程序看起来像是在同时运行(例如,一边浏览网页一边播放音乐)。这就是引入进程和线程的重要意义。
1.2. 快速入门
1.2.1 开发环境准备
如果您是第一次阅读本文档,请先阅读《入门指南/开发环境准备/Easy-Eai 编译环境的准备与更新》,并按照其中的步骤搭建编译环境。
在 PC 上的 Ubuntu 系统中执行 run 脚本,进入 EASY-EAI 编译环境。具体如下。
cd ~/develop_environment./run.sh 22041.2.2 下载源代码并编译示例
在 EASY-EAI 编译环境下,创建用于管理源代码仓库的目录。
cd /optmkdir EASY-EAI-Toolkitcd EASY-EAI-Toolkithttps://dl.dragonwake.com/download/rv1126b/embedded/EASY-EAI-Toolkit-1126B/Demos.zip
从上述链接下载 Demos.zip 压缩文件,并将其上传到虚拟机的 /opt/EASY-EAI-Toolkit 目录中,然后解压。 进入对应示例的目录并执行编译操作。具体命令如下。
cd EASY-EAI-Toolkit-1126B/Demos/common-system_opt/./build.sh💡 注意:由于依赖库放置在开发板上,因此在交叉编译过程中必须保持 /mnt 挂载。

1.2.2 下载源代码并编译示例 图27
1.2.3 运行示例
通过串口调试或 SSH 调试进入开发板后台,并移动到示例所在位置。如下所示。
cd /userdata/Demo/common-system_opt
1.2.3 运行示例 图28
示例运行命令如下。
./test-thread-opt1.2.4 运行结果
运行结果如下所示。

1.2.4 运行结果 图29
关于 API 的详细说明以及 API 的调用方式(本示例的源代码),请参考以下说明。
1.3. 线程操作 API 说明
1.3.1 包含/引用方法
EASY EAI api 库位于本仓库的 easyeai-api 目录中。为了让客户能够在本地项目中直接调用 EASY EAI api 库,下面列出了项目中需要链接的库和头文件等内容。
| 说明 | CMake 中的写法 | Makefile 中的写法 |
|---|---|---|
| api.cmake | ${common_root}/system_opt/api.cmake | 无 |
| 头文件目录 | ${SYSTEM_OPT_INCLUDE_DIRS} | -I ../../easyeai-api/common/system_opt |
| 源文件目录 | ${SYSTEM_OPT_SOURCE_DIRS} | ../../easyeai-api/common/system_opt |
| 库文件目录 | 无 | 无 |
| 库链接参数 | ${SYSTEM_OPT_LIBS} | 无 |
API 源代码路径为 EASY-EAI-Toolkit-1126B/easyeai-api/common/system_opt/。用户可以通过源代码查看接口的实现,也可以直接修改源代码。
1.3.2 线程任务原型
线程任务的原型如下所示。线程任务是程序执行的最小单位,定义如下。
typedef void \*(\*ThreadEntryPtrType)(void \*);1.3.3 线程创建函数
线程创建函数的原型如下所示。
int32_t CreateNormalThread(ThreadEntryPtrType entry, void \*para, pthread_t \*pid);具体说明如下。
| 函数名:CreateNormalThread() | 详细说明 |
|---|---|
| 头文件 | easyeai-api/common/system_opt/system_opt.h |
| 输入参数 | entry:作为线程主体的执行函数 para:传递给线程的参数(作为共享变量使用) pid:指向新创建的 pthread_t 类型对象的指针 |
| 返回值 | 创建失败时返回 -1 创建成功时返回 0 |
| 注意事项 | pid 变量用于存储系统分配的线程 ID。传入 NULL 会导致程序异常退出。 |
1.3.4 执行 Shell 命令 - 调用 system()
执行 Shell 命令的函数原型如下。
int32_t exec_cmd_by_system(const char \*cmd);该函数通过调用 system() 实现。具体说明如下。
| 函数名:exec_cmd_by_system() | 详细说明 |
|---|---|
| 头文件 | easyeai-api/common/system_opt/system_opt.h |
| 输入参数 | cmd:Shell 命令 |
| 返回值 | 如果 fork 失败,system() 函数返回 -1 如果 exec 成功且命令正常结束,则返回该命令通过 exit 或 return 返回的值。 |
| 注意事项 | 1. 为了在出错时获得更有用的信息,建议在 system() 执行后监控 errno 值。 2. 异步(非阻塞)执行注意事项:为了将命令转入后台,需添加 & 并同时重定向输出。否则将以阻塞方式执行。 |
1.3.5 执行 Shell 命令 - 调用 popen()
执行 Shell 命令的函数原型如下。
int32_t exec_cmd_by_popen(const char \*cmd, char \*result);该函数通过调用 popen() 实现,并可获取执行结果。具体说明如下。
| 函数名:exec_cmd_by_popen() | 详细说明 |
|---|---|
| 头文件 | easyeai-api/common/system_opt/system_opt.h |
| 输入参数 | cmd:Shell 命令 result:Shell 命令执行后,返回结果会存储到该内存区域中 |
| 返回值 | 调用失败时返回 -1 调用成功时返回 0(结果已正常写入 result) |
| 注意事项 | 如果命令执行失败,子进程会将错误信息打印到标准错误输出,因此父进程无法获取该信息。 如果需要捕获错误信息,请将子进程的错误输出重定向到标准输出(2>&1)。这样父进程就可以获取错误信息。 示例:exec_cmd_by_popen(“ls 2>&1”, result); |
1.4. 线程操作 API 使用示例
线程操作 API 使用示例代码的路径如下:
EASY-EAI-Toolkit-1126B/Demos/common-system_opt/test-thread-opt.c 线程创建示例由“线程执行主体”和“线程创建操作”两部分组成。
线程执行主体如下所示。
void *testThreadBody(void *arg){int *share_para = (int *)arg;while(1){printf("[tesThread] --- share_para = %d\n", *share_para);if(*share_para > 10){printf("[tesThread] --- exit\n");break;}sleep(1);}pthread_exit(NULL);}线程创建操作如下所示。pId 变量用于存储进程(线程)ID,share_para 变量用于保存输入参数。
pthread_t pId;int share_para = 0;if(0 == CreateNormalThread(testThreadBody, &share_para,&pId)){while(1){printf("[mainThread] --- \n");share_para++;sleep(1);}}