眉山市网站建设_网站建设公司_Redis_seo优化
2025/12/26 9:36:38 网站建设 项目流程

1.互斥量共享内存的例子

一个使用互斥量(Mutex)实现两个线程共享内存的示例,具体场景是一个线程模拟读取传感器数据并写入数组,另一个线程从数组读取数据并处理(显示 / 存储),核心是通过互斥量保证数据访问的线程安全。

实现思路

  1. 共享资源定义:定义一个数组作为传感器数据缓冲区,同时定义一个互斥量保护这个数组的访问。
  2. 线程 1(生产者):模拟传感器数据采集,每次生成随机数据后,先加锁互斥量,写入数组,解锁后休眠一段时间(模拟采样间隔)。
  3. 线程 2(消费者):循环读取数组数据,先加锁互斥量,读取并处理数据(打印显示),解锁后休眠一段时间(模拟处理间隔)。
  4. 主线程:创建并启动两个子线程,等待线程结束后释放资源。
#include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <unistd.h> #include <time.h> // 定义共享数据和互斥量 #define BUFFER_SIZE 5 // 传感器数据缓冲区大小 int sensor_data[BUFFER_SIZE]; // 共享数组(传感器数据缓冲区) pthread_mutex_t data_mutex; // 保护共享数组的互斥量 // 传感器数据生成函数(模拟读取真实传感器数据) int generate_sensor_data() { // 生成0-99的随机数模拟传感器数据 return rand() % 100; } // 线程1:生产者 - 读取传感器数据并写入数组 void* sensor_reader_thread(void* arg) { (void)arg; // 忽略未使用的参数 int index = 0; // 数组写入索引 while (1) { // 1. 生成模拟传感器数据 int new_data = generate_sensor_data(); // 2. 加锁互斥量,保证独占访问共享数组 pthread_mutex_lock(&data_mutex); // 3. 写入共享数组(循环覆盖) sensor_data[index] = new_data; printf("[生产者线程] 写入数据: %d 到数组索引 %d\n", new_data, index); index = (index + 1) % BUFFER_SIZE; // 循环索引,满了从头覆盖 // 4. 解锁互斥量,释放共享资源 pthread_mutex_unlock(&data_mutex); // 模拟传感器采样间隔(1秒采集一次) sleep(1); } return NULL; } // 线程2:消费者 - 从数组读取数据并处理(打印/存储) void* data_processor_thread(void* arg) { (void)arg; // 忽略未使用的参数 int index = 0; // 数组读取索引 while (1) { // 1. 加锁互斥量,保证独占访问共享数组 pthread_mutex_lock(&data_mutex); // 2. 读取共享数组数据并处理 int read_data = sensor_data[index]; printf("[消费者线程] 读取数据: %d 从数组索引 %d\n", read_data, index); index = (index + 1) % BUFFER_SIZE; // 循环索引,同步读取位置 // 3. 解锁互斥量,释放共享资源 pthread_mutex_unlock(&data_mutex); // 模拟数据处理间隔(1秒处理一次) sleep(1); } return NULL; } int main() { // 初始化随机数种子(用于模拟传感器数据) srand((unsigned int)time(NULL)); // 初始化互斥量(必须初始化,否则会导致未定义行为) if (pthread_mutex_init(&data_mutex, NULL) != 0) { perror("互斥量初始化失败"); return 1; } // 初始化共享数组为0 for (int i = 0; i < BUFFER_SIZE; i++) { sensor_data[i] = 0; } // 定义线程ID pthread_t reader_thread, processor_thread; // 创建生产者线程(传感器数据读取) if (pthread_create(&reader_thread, NULL, sensor_reader_thread, NULL) != 0) { perror("创建生产者线程失败"); pthread_mutex_destroy(&data_mutex); // 清理互斥量 return 1; } // 创建消费者线程(数据处理) if (pthread_create(&processor_thread, NULL, data_processor_thread, NULL) != 0) { perror("创建消费者线程失败"); pthread_cancel(reader_thread); // 取消已创建的线程 pthread_mutex_destroy(&data_mutex); // 清理互斥量 return 1; } // 等待线程结束(这里用无限循环,实际场景可设置退出条件) pthread_join(reader_thread, NULL); pthread_join(processor_thread, NULL); // 销毁互斥量(释放资源) pthread_mutex_destroy(&data_mutex); return 0; }

2.全局变量的方式

#include <rtthread.h> #include <rtdevice.h> #include <board.h> /* -------------------------- 全局共享资源定义 -------------------------- */ #define SENSOR_BUFFER_SIZE 5 // 传感器数据缓冲区大小 static rt_int32_t sensor_buffer[SENSOR_BUFFER_SIZE] = {0}; // 共享数组 // 原子变量:写入索引(线程用)、读取索引(中断用)、数据有效标志 static rt_atomic_t write_idx = RT_ATOMIC_INIT(0); static rt_atomic_t read_idx = RT_ATOMIC_INIT(0); static rt_atomic_t buffer_valid[SENSOR_BUFFER_SIZE] = { RT_ATOMIC_INIT(0), RT_ATOMIC_INIT(0), RT_ATOMIC_INIT(0), RT_ATOMIC_INIT(0), RT_ATOMIC_INIT(0) }; /* -------------------------- 传感器数据模拟 -------------------------- */ // 模拟读取传感器数据(返回0-99随机数) static rt_int32_t sensor_read_data(void) { static rt_uint32_t seed = 12345; seed = seed * 1103515245 + 12345; return (rt_int32_t)((seed / 65536) % 100); } /* -------------------------- 线程:传感器数据采集(生产者) -------------------------- */ static void sensor_collect_thread(void *parameter) { rt_int32_t idx; rt_int32_t data; while (1) { // 1. 读取模拟传感器数据 data = sensor_read_data(); // 2. 获取当前写入索引(原子操作,避免多线程竞争) idx = rt_atomic_read(&write_idx); // 3. 安全写入共享数组(RT_ATOMIC_SECTION 保证操作原子性) RT_ATOMIC_SECTION_BEGIN sensor_buffer[idx] = data; // 写入数据 rt_atomic_set(&buffer_valid[idx], 1); // 标记该位置数据有效 RT_ATOMIC_SECTION_END // 4. 更新写入索引(循环覆盖) rt_atomic_set(&write_idx, (idx + 1) % SENSOR_BUFFER_SIZE); rt_kprintf("[采集线程] 写入数据: %d 到索引 %d\n", data, idx); // 模拟传感器采样间隔(500ms) rt_thread_mdelay(500); } } /* -------------------------- 中断服务程序(ISR):数据读取(消费者) -------------------------- */ // 定时器中断服务函数(模拟硬件中断,替代实际传感器中断) static rt_err_t timer_isr_hook(rt_device_t dev, rt_size_t size) { rt_int32_t idx; rt_int32_t data; // 中断上下文:禁止调用任何可能休眠的函数(如rt_thread_mdelay、rt_kprintf慎用) // 1. 获取当前读取索引(原子操作) idx = rt_atomic_read(&read_idx); // 2. 检查数据是否有效,有效则读取 if (rt_atomic_read(&buffer_valid[idx]) == 1) { // 原子操作读取数据,保证完整性 RT_ATOMIC_SECTION_BEGIN data = sensor_buffer[idx]; // 读取数据 rt_atomic_set(&buffer_valid[idx], 0); // 标记该位置数据已读取 RT_ATOMIC_SECTION_END // 中断中尽量简化操作,这里仅打印(实际场景可写入存储/寄存器) rt_kprintf("[中断ISR] 读取数据: %d 从索引 %d\n", data, idx); // 3. 更新读取索引(循环读取) rt_atomic_set(&read_idx, (idx + 1) % SENSOR_BUFFER_SIZE); } else { // 无有效数据时的提示(可选) // rt_kprintf("[中断ISR] 索引 %d 无有效数据\n", idx); } return RT_EOK; } /* -------------------------- 初始化函数 -------------------------- */ int sensor_interrupt_share_demo(void) { rt_thread_t collect_thread; rt_device_t timer_dev; struct rt_device_timer_info timer_info; // 1. 创建传感器采集线程 collect_thread = rt_thread_create( "sensor_collect", // 线程名称 sensor_collect_thread, // 线程入口函数 RT_NULL, // 线程参数 1024, // 栈大小 10, // 优先级(数值越小优先级越高) 20 // 时间片 ); if (collect_thread != RT_NULL) { rt_thread_startup(collect_thread); rt_kprintf("传感器采集线程创建成功\n"); } else { rt_kprintf("传感器采集线程创建失败\n"); return -RT_ERROR; } // 2. 初始化定时器设备(模拟硬件中断,使用RT-Thread系统定时器) timer_dev = rt_device_find("timer0"); if (timer_dev == RT_NULL) { rt_kprintf("定时器设备查找失败\n"); return -RT_ERROR; } // 3. 打开定时器设备 if (rt_device_open(timer_dev, RT_DEVICE_OFLAG_RDWR) != RT_EOK) { rt_kprintf("定时器设备打开失败\n"); return -RT_ERROR; } // 4. 设置定时器回调函数(中断服务程序) rt_device_set_rx_indicate(timer_dev, timer_isr_hook); // 5. 配置定时器参数(1秒触发一次中断) timer_info.period = 1000; // 周期(ms) timer_info.mode = RT_DEVICE_TIMER_PERIODIC; // 周期性触发 rt_device_control(timer_dev, RT_DEVICE_CTRL_TIMER_SET_PERIOD, &timer_info); // 6. 启动定时器 rt_device_control(timer_dev, RT_DEVICE_CTRL_TIMER_START, RT_NULL); rt_kprintf("定时器中断初始化成功,1秒触发一次\n"); return RT_EOK; } // 导出到RT-Thread的msh命令 MSH_CMD_EXPORT(sensor_interrupt_share_demo, sensor interrupt share memory demo);

3.避坑

避坑1:

互斥信号量不要在线程和中断之间使用

避坑2:

全局变量的方式,不要用在线程和线程之间

读线程可能频繁 “读不到数据”(因为写标记被占用),数据更新率下降。

无原子性保护:状态标记本身的读写可能被打断,导致逻辑异常。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询