C语言多线程同时访问变量问题咨询(传感器执行器场景)
解决C语言多线程传感器-执行器应用的同步问题
嘿,我懂你现在面临的麻烦——两个线程同时操作共享变量sensor_values,这种读写竞争绝对会搞出乱子:要么读出来的是半更新的数据,要么程序直接出现莫名其妙的行为,完全不符合预期。别慌,咱们用线程同步机制就能搞定这个问题,最常用的就是互斥锁,下面给你一步步拆解。
首先,先明确核心问题:C语言里的普通变量没有线程安全保障,当一个线程在读取变量的同时,另一个线程写入,这属于未定义行为,系统完全不保证结果的正确性。
方案一:用互斥锁(pthread_mutex_t)实现排他访问
互斥锁的作用很简单:同一时间只允许一个线程持有锁,持有锁的线程才能访问共享资源,其他线程必须等待锁释放。这就彻底避免了读写冲突。
给你修改后的完整示例代码:
#include <pthread.h> #include <stdio.h> #include <unistd.h> // 共享传感器数据变量 int sensor_values; // 定义互斥锁,保护共享变量 pthread_mutex_t sensor_mutex; // 模拟从硬件读取传感器数据的函数 int some_sensor_read_function() { // 这里替换成你的实际硬件读取逻辑,比如从GPIO或者串口读数据 static int val = 0; return val++ % 100; // 模拟数据变化 } // 读传感器线程:负责读取并解析传感器数据 void* read_sensor(void* arg) { while (1) { // 加锁:确保读取时没有线程在写 pthread_mutex_lock(&sensor_mutex); int current_val = sensor_values; printf("[读线程] 读取到传感器值:%d\n", current_val); // 解锁:释放锁让其他线程可以访问 pthread_mutex_unlock(&sensor_mutex); // 模拟传感器读取间隔,实际根据硬件调整 sleep(1); } return NULL; } // 执行器控制线程:根据传感器值控制执行器启停 void* control_actuator(void* arg) { while (1) { // 加锁:确保修改共享变量时没有线程在读 pthread_mutex_lock(&sensor_mutex); // 更新传感器值(实际是从硬件读取后赋值) sensor_values = some_sensor_read_function(); // 根据值判断执行器动作 if (sensor_values > 50) { printf("[控制线程] 传感器值超过阈值,启动执行器\n"); // 这里添加你的执行器启动逻辑 } else { printf("[控制线程] 传感器值低于阈值,停止执行器\n"); // 这里添加你的执行器停止逻辑 } // 解锁 pthread_mutex_unlock(&sensor_mutex); // 模拟控制间隔,实际根据需求调整 sleep(2); } return NULL; } int main() { pthread_t read_thread, control_thread; // 初始化互斥锁,一定要做这一步! if (pthread_mutex_init(&sensor_mutex, NULL) != 0) { perror("互斥锁初始化失败"); return 1; } // 创建两个线程 if (pthread_create(&read_thread, NULL, read_sensor, NULL) != 0) { perror("创建读传感器线程失败"); return 1; } if (pthread_create(&control_thread, NULL, control_actuator, NULL) != 0) { perror("创建执行器控制线程失败"); return 1; } // 等待线程结束(这里因为是死循环,实际可能需要信号来终止) pthread_join(read_thread, NULL); pthread_join(control_thread, NULL); // 销毁互斥锁,释放资源 pthread_mutex_destroy(&sensor_mutex); return 0; }
关键注意事项
- 锁的配对:加锁后必须解锁,哪怕函数中途出错返回,否则会导致死锁(其他线程永远拿不到锁)。如果你的代码里有分支提前返回,可以用
goto统一处理解锁,或者在每个返回前手动解锁。 - 锁的粒度:不要在持有锁的时候执行耗时操作(比如长时间的IO、sleep),否则会让另一个线程一直等待,拖慢程序响应速度。
- 初始化与销毁:互斥锁必须用
pthread_mutex_init初始化,用完后用pthread_mutex_destroy销毁,避免资源泄漏。
备选方案:读写锁(pthread_rwlock_t)
如果你的应用里读操作远多于写操作,读写锁会比互斥锁更高效——它允许多个读线程同时持有读锁,只有写线程需要独占锁。示例用法如下:
#include <pthread.h> pthread_rwlock_t sensor_rwlock; // 读线程中使用读锁 void* read_sensor(void* arg) { while(1) { pthread_rwlock_rdlock(&sensor_rwlock); int val = sensor_values; pthread_rwlock_unlock(&sensor_rwlock); // ...其他逻辑 } } // 写线程中使用写锁 void* control_actuator(void* arg) { while(1) { pthread_rwlock_wrlock(&sensor_rwlock); sensor_values = new_val; pthread_rwlock_unlock(&sensor_rwlock); // ...其他逻辑 } }
读写锁的初始化和销毁用pthread_rwlock_init和pthread_rwlock_destroy,和互斥锁类似。
这样处理后,你的两个线程就能安全地共享sensor_values变量,不会再出现读写冲突的问题啦。
内容的提问来源于stack exchange,提问作者Mário Marques
相关产品推荐
相关产品推荐

