概念先知道
- POSIX:一套操作系统接口标准(pthread 线程、semaphore 信号量、mqueue 消息队列等)。在 Linux 上写多线程程序用的就是这些 API。
- 兼容层(Compatibility Layer):让嵌入式系统“假装”自己是 Linux——FreeRTOS 上实现 POSIX API,代码可先在 PC 上写好、再移植到单片机。
- pthread:POSIX 线程。
pthread_create创建线程,pthread_mutex_lock/unlock加解锁,pthread_cond_wait/signal条件变量,pthread_barrier_wait栅栏同步。 - POSIX 信号量与消息队列:
sem_open/sem_wait/sem_post、mq_open/mq_send/mq_receive,是任务间同步和传数据的标准接口。 - 与 FreeRTOS 原生 API 的关系:兼容层底层仍是 FreeRTOS 的任务/队列/信号量,只是换了 POSIX 的“皮肤”。选哪种取决于习惯与代码可移植性。
例程功能简介
本页对应博流官方 SDK 的 freertos_posix 例程(examples/posix/freertos_posix),演示 FreeRTOS POSIX 兼容层的用法:
- 例程是一个 POSIX API 测试套件:9 组测试覆盖 pthread(创建/属性/互斥锁/条件变量/栅栏)、信号量、消息队列、时钟定时器、sched/unistd;
- 通过 shell 命令
posix_test一次跑全部,posix_test_single <group>只跑指定组; - 每个用例统计 run/pass/fail/skip,最后
print_test_summary()打印汇总; - 开启了
CONFIG_POSIX=y后,工程中即可直接#include <pthread.h>、<semaphore.h>、<mqueue.h>等标准头文件。
提示
本页代码量不大但概念密:想动手写自己的多线程代码,先跑通 posix_test,再参考 test/ 目录下的用例写法。
操作步骤
在终端进入 SDK 的 POSIX 兼容层例程目录(前提:已按快速开始(Linux)或Windows搭建好环境):
cd examples/posix/freertos_posix例程 defconfig 已含 CONFIG_POSIX=y;若你自己新建工程,需要在 defconfig 中加上该行,或执行 make menuconfig 勾选 POSIX 支持后保存。
grep CONFIG_POSIX defconfig执行编译命令。Ai-M62(BL616)与 Ai-M61(BL618)同属一个系列,统一填写引脚最少的 bl616 即可:
make CHIP=bl616 BOARD=bl616dk用 USB 线连接开发板,按住 BOOT 键(Ai-M61-32S-Kit 为 IO2)不放、短按 EN/RST 进入下载模式,然后执行烧录(把串口号换成实际值):
make flash CHIP=bl616 COMX=/dev/ttyUSB0打开串口助手(波特率 2000000),在 bouffalolab /> 提示符输入 posix_test 回车,串口依次运行 9 组测试(pthread、pthread_attr、mutex、cond、barrier、sem、mqueue、clock、sched)并打印 PASSED/FAILED 汇总;也可用 posix_test_single pthread 只跑一组。
代码执行流程
例程从启动到测试完成的流程如下:
例程调用的 API 介绍
pthread_create / pthread_join / pthread_attr_*(...)
创建/等待线程,设置线程属性(分离状态、栈大小、调度参数)。对应 test/test_pthread.c 等用例。
参数:
thread:线程 ID 输出attr:线程属性(可NULL用默认值)start_routine/arg:线程函数与参数
返回值:0 成功;错误码失败
pthread_mutex_lock / pthread_mutex_unlock(mutex)
互斥锁加锁/解锁,保护共享数据。测试中还覆盖了属性(pthread_mutexattr_*)与超时变体(pthread_mutex_timedlock)。
参数:
mutex:互斥锁对象
返回值:0 成功;错误码失败
sem_open / sem_wait / sem_post(...)
创建命名信号量并执行 P/V 操作(等待/释放),用于任务同步。
参数:
name:信号量名(如/sem0)value:初值sem:信号量指针
返回值:0 成功;-1 失败并置 errno
mq_open / mq_send / mq_receive(...)
创建消息队列并收发消息,是任务间传数据(带优先级)的标准接口。
参数:
name:队列名attr:队列属性(长度、消息大小)msg/prio:消息数据与优先级
返回值:mqd_t 描述符 / 成功发送字节数;失败返回 (mqd_t)-1
完整代码
以下为 posix/freertos_posix/main.c 完整源码,与官方示例一致,默认折叠,点击展开(各测试组在 test/ 子目录):
📜 点击展开 posix/freertos_posix/main.c 完整代码
#include <stdio.h>
#include <string.h>
#include "board.h"
#include "shell.h"
#include "bflb_core.h"
#include <FreeRTOS.h>
#include "task.h"
#include "test_common.h"
/* Forward declaration for shell_init_with_task (not declared in shell.h) */
extern void shell_init_with_task(struct bflb_device_s *uart);
/* Stack overflow hook - called when FreeRTOS detects stack overflow */
void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName)
{
printf("\r\n[STACK OVERFLOW] Task: %s\r\n", pcTaskName);
while (1) {
/* Halt to allow debugging */
}
}
/* Global test counters */
int g_tests_run = 0;
int g_tests_passed = 0;
int g_tests_failed = 0;
int g_tests_skipped = 0;
/* External declarations for each test group */
extern void test_pthread_run(void);
extern void test_pthread_attr_run(void);
extern void test_pthread_mutex_run(void);
extern void test_pthread_cond_run(void);
extern void test_pthread_barrier_run(void);
extern void test_semaphore_run(void);
extern void test_mqueue_run(void);
extern void test_clock_timer_run(void);
extern void test_sched_unistd_run(void);
/* Run all tests */
static void run_all_tests(void)
{
printf("\r\n===== POSIX API Test Suite Start =====\r\n\r\n");
/* Reset counters */
g_tests_run = 0;
g_tests_passed = 0;
g_tests_failed = 0;
g_tests_skipped = 0;
printf("--- 1. pthread tests ---\r\n");
test_pthread_run();
printf("\r\n--- 2. pthread_attr tests ---\r\n");
test_pthread_attr_run();
printf("\r\n--- 3. pthread_mutex tests ---\r\n");
test_pthread_mutex_run();
printf("\r\n--- 4. pthread_cond tests ---\r\n");
test_pthread_cond_run();
printf("\r\n--- 5. pthread_barrier tests ---\r\n");
test_pthread_barrier_run();
printf("\r\n--- 6. semaphore tests ---\r\n");
test_semaphore_run();
printf("\r\n--- 7. mqueue tests ---\r\n");
test_mqueue_run();
printf("\r\n--- 8. clock/timer tests ---\r\n");
test_clock_timer_run();
printf("\r\n--- 9. sched/unistd tests ---\r\n");
test_sched_unistd_run();
print_test_summary();
}
/* Shell command: run all tests */
static void cmd_posix_test(int argc, char **argv)
{
/* Run tests directly in shell task context */
run_all_tests();
}
SHELL_CMD_EXPORT_ALIAS(cmd_posix_test, posix_test, Run all POSIX tests);
/* Shell command: run single test group */
static void cmd_posix_test_single(int argc, char **argv)
{
if (argc < 2) {
printf("Usage: posix_test_single <group>\r\n");
printf("Groups: pthread, pthread_attr, mutex, cond, barrier, sem, mqueue, clock, sched\r\n");
return;
}
g_tests_run = 0;
g_tests_passed = 0;
g_tests_failed = 0;
g_tests_skipped = 0;
if (strcmp(argv[1], "pthread") == 0) {
test_pthread_run();
} else if (strcmp(argv[1], "pthread_attr") == 0) {
test_pthread_attr_run();
} else if (strcmp(argv[1], "mutex") == 0) {
test_pthread_mutex_run();
} else if (strcmp(argv[1], "cond") == 0) {
test_pthread_cond_run();
} else if (strcmp(argv[1], "barrier") == 0) {
test_pthread_barrier_run();
} else if (strcmp(argv[1], "sem") == 0) {
test_semaphore_run();
} else if (strcmp(argv[1], "mqueue") == 0) {
test_mqueue_run();
} else if (strcmp(argv[1], "clock") == 0) {
test_clock_timer_run();
} else if (strcmp(argv[1], "sched") == 0) {
test_sched_unistd_run();
} else {
printf("Unknown test group: %s\r\n", argv[1]);
return;
}
print_test_summary();
}
SHELL_CMD_EXPORT_ALIAS(cmd_posix_test_single, posix_test_single, Run single POSIX test group);
int main(void)
{
board_init();
printf("\r\n========================================\r\n");
printf(" FreeRTOS POSIX Test Application\r\n");
printf("========================================\r\n");
printf("\r\nShell commands:\r\n");
printf(" posix_test - Run all tests\r\n");
printf(" posix_test_single - Run single test group\r\n");
printf("\r\n");
/* Initialize shell task */
struct bflb_device_s *uart0 = bflb_device_get_by_name("uart0");
shell_init_with_task(uart0);
vTaskStartScheduler(); /* starts scheduler, never returns */
while (1) {
/* Should never reach here */
}
}FAQ
编译报找不到 pthread.h / semaphore.h?
说明工程没开 POSIX 兼容层。在 defconfig 中加入 CONFIG_POSIX=y(例程已带),或 make menuconfig 勾选后重新编译。
POSIX 接口和 FreeRTOS 原生接口,用哪个好?
没有绝对优劣:POSIX 接口可移植性好(代码可搬到 Linux 或其他 RTOS),FreeRTOS 原生接口更贴近底层、文档多。课程/作业常要求“标准接口”,工程实践常两者混用。
`posix_test` 跑出 FAILED 怎么办?
先确认板子型号与 defconfig 与例程一致(PSRAM/堆大小影响线程创建)。若个别用例失败,多半是栈或堆配置偏小,调大 configTOTAL_HEAP_SIZE 或线程 stacksize 再试。
测试耗时多久?
9 组全跑约几秒到十几秒,取决于时钟/定时器测试的等待时间。只调试某类接口时用 posix_test_single <group> 更快。

