
1) 【一句话结论】在设备状态监控系统中,多线程处理多个传感器上报数据时,需通过线程同步机制(如互斥锁、信号量、条件变量)协调共享资源访问,避免数据竞争与死锁,核心是保护共享数据结构并控制并发数量与线程间通信。
2) 【原理/概念讲解】老师口吻:多线程并发访问共享资源(如传感器数据队列)会引发两类问题——数据竞争(共享变量未同步修改导致数据不一致)和死锁(线程互相等待资源形成循环等待)。线程同步机制的作用是解决这些问题:
3) 【对比与适用场景】
| 机制 | 定义 | 特性 | 使用场景 | 注意点 |
|---|---|---|---|---|
| 互斥锁 | 保护共享资源的排他性访问 | 独占式,同一时间仅一个线程持有 | 保护共享数据结构(如传感器数据队列) | 避免死锁需遵循“持有并等待”原则(如先获取所有锁再释放) |
| 信号量 | 控制并发访问的资源数量 | 计数器,允许多个线程同时访问,上限为信号量值 | 控制同时上报的传感器数量(如队列容量为10,信号量初始为10) | 需初始化正确,避免死锁(如信号量值设为队列容量) |
| 条件变量 | 线程间等待/通知机制 | 等待条件满足时唤醒 | 传感器上报后,处理线程等待数据,处理完成后通知其他线程 | 需与互斥锁配合使用(如等待前先获取互斥锁) |
4) 【示例】(伪代码)
// 共享资源(传感器数据队列)
std::queue<std::pair<int, float>> sensor_queue;
pthread_mutex_t queue_mutex = PTHREAD_MUTEX_INITIALIZER; // 互斥锁保护队列
sem_t queue_sem; // 信号量控制队列长度(假设队列容量为10)
pthread_cond_t queue_not_empty = PTHREAD_COND_INITIALIZER; // 条件变量
// 传感器上报函数(生产者)
void sensor_report(int sensor_id, float data) {
// 获取信号量,控制队列长度
sem_wait(&queue_sem);
// 获取互斥锁,保护队列操作
pthread_mutex_lock(&queue_mutex);
// 将数据加入队列
sensor_queue.push({sensor_id, data});
pthread_mutex_unlock(&queue_mutex);
// 释放信号量,允许其他传感器写入
sem_post(&queue_sem);
// 通知处理线程(队列非空)
pthread_cond_signal(&queue_not_empty);
}
// 处理线程函数(消费者)
void* process_thread(void* arg) {
while (true) {
// 等待队列非空(用条件变量)
pthread_cond_wait(&queue_not_empty, &queue_mutex);
// 从队列取数据
pthread_mutex_lock(&queue_mutex);
if (!sensor_queue.empty()) {
auto data = sensor_queue.front();
sensor_queue.pop();
pthread_mutex_unlock(&queue_mutex);
// 处理数据(如状态分析、报警)
}
}
}
5) 【面试口播版答案】(约90秒)
“在设备状态监控系统中,多个传感器同时上报数据时,多线程处理的关键是使用线程同步机制避免数据竞争和死锁。核心思路是用互斥锁保护共享数据结构(如传感器数据队列),用信号量控制队列的并发写入数量(比如限制同时上报的传感器数量不超过队列容量),用条件变量实现传感器上报与处理线程的同步(比如传感器写入后通知处理线程,处理线程等待数据后处理)。具体来说,比如传感器上报时先获取信号量(控制队列长度),再用互斥锁保护队列操作,将数据加入队列后释放信号量并通知处理线程;处理线程通过条件变量等待队列非空,获取数据后处理。这样既保证了数据一致性,又避免了死锁。”
6) 【追问清单】
7) 【常见坑/雷区】