场景 1:共享全局变量(使用互斥锁)
问题:多个任务同时修改全局计数器导致数据不一致
解决方案:使用互斥锁保护临界区
#include <rtthread.h>
static int counter = 0;
static struct rt_mutex counter_mutex;
void increment_counter(void) {
rt_mutex_take(&counter_mutex, RT_WAITING_FOREVER); // 上锁
counter++; // 安全操作
rt_kprintf("Counter: %d\n", counter);
rt_mutex_release(&counter_mutex); // 解锁
}
void thread_entry(void* param) {
while (1) {
increment_counter(); // 多个任务调用同一函数
rt_thread_mdelay(50);
}
}
int main(void) {
rt_mutex_init(&counter_mutex, "cnt_mtx", RT_IPC_FLAG_FIFO);
// 创建3个任务
for (int i = 0; i < 3; i++) {
rt_thread_t tid = rt_thread_create("t", thread_entry, RT_NULL, 512, 25, 10);
rt_thread_startup(tid);
}
return 0;
}
场景 2:共享硬件资源(使用信号量)
问题:多个任务同时操作串口导致输出混乱
解决方案:使用二值信号量实现互斥访问
static rt_sem_t uart_sem;
void uart_print(const char* msg) {
rt_sem_take(uart_sem, RT_WAITING_FOREVER); // 获取信号量
rt_device_write(uart_dev, 0, msg, rt_strlen(msg)); // 安全操作
rt_sem_release(uart_sem); // 释放信号量
}
void task1_entry(void* param) {
while (1) {
uart_print("Task1 sending data\n");
rt_thread_mdelay(100);
}
}
void task2_entry(void* param) {
while (1) {
uart_print("Task2 sending log\n");
rt_thread_mdelay(150);
}
}
void app_init() {
// 创建二值信号量(初始值为1)
uart_sem = rt_sem_create("uart_sem", 1, RT_IPC_FLAG_FIFO);
// 初始化串口设备...
uart_dev = rt_device_find("uart1");
rt_device_open(uart_dev, RT_DEVICE_FLAG_RDWR);
}
场景 3:非线程安全库函数(使用线程局部存储)
问题:多个任务同时使用 strtok 等非可重入函数
解决方案:使用可重入版本或线程局部变量
#include <string.h>
// 线程安全的strtok版本
char* safe_strtok(char* str, const char* delim) {
static RT_THREAD_LOCAL char* save_ptr; // 线程局部存储
return strtok_r(str, delim, &save_ptr);
}
void parse_data(char* data) {
char* token = safe_strtok(data, ",");
while (token) {
rt_kprintf("Token: %s\n", token);
token = safe_strtok(NULL, ",");
}
}
场景 4:复杂共享资源(使用消息队列)
问题:多个任务需要访问复杂数据结构(如链表)
解决方案:通过消息队列委托给专用处理线程
static rt_mq_t data_mq;
// 数据处理线程(唯一访问者)
void data_processor_entry(void* param) {
struct data_packet packet;
while (1) {
if (rt_mq_recv(data_mq, &packet, sizeof(packet), RT_WAITING_FOREVER) > 0) {
// 安全处理共享数据
process_data(&packet);
}
}
}
// 其他任务通过消息队列提交请求
void submit_data_request(int type, void* data) {
struct data_packet packet = {type, data};
rt_mq_send(data_mq, &packet, sizeof(packet));
}
void worker_task_entry(void* param) {
while (1) {
void* data = collect_data();
submit_data_request(DATA_PROCESS, data); // 不直接操作共享资源
rt_thread_mdelay(200);
}
}
场景 5:读多写少场景(使用读写锁)
问题:配置数据被频繁读取但偶尔修改
解决方案:使用读写锁提高并发性
static rt_rwlock_t config_rwlock;
static struct app_config global_config;
// 读取配置(多个任务可同时读)
void get_config(struct app_config* out) {
rt_rwlock_rdlock(&config_rwlock);
memcpy(out, &global_config, sizeof(struct app_config));
rt_rwlock_rdunlock(&config_rwlock);
}
// 更新配置(独占访问)
void update_config(const struct app_config* new_cfg) {
rt_rwlock_wrlock(&config_rwlock);
memcpy(&global_config, new_cfg, sizeof(struct app_config));
rt_rwlock_wrunlock(&config_rwlock);
}
最佳实践总结:
- 最小化共享:尽量设计无状态函数,使用局部变量
- 锁粒度控制:
// 错误示范:锁范围过大 rt_mutex_take(&lock); complex_operation1(); complex_operation2(); // 阻塞其他任务过久 rt_mutex_release(&lock); // 正确做法:只保护真正共享的部分 complex_operation1(); // 非临界区操作 rt_mutex_take(&lock); critical_section(); // 快速完成 rt_mutex_release(&lock); complex_operation2(); - 避免锁嵌套:防止死锁
- 优先使用消息队列:减少直接共享
- 原子操作:简单计数使用原子变量
#include <stdatomic.h> atomic_int safe_counter = ATOMIC_VAR_INIT(0); void increment_atomic() { atomic_fetch_add(&safe_counter, 1); }
通过合理选择同步机制,可以确保多任务安全共享函数,同时保持系统效率。
221

被折叠的 条评论
为什么被折叠?



