C语言多线程场景下对semaphore信号量做递减操作时哪里出错了?
信号量使用错误排查与修复
现有代码的核心问题
- 信号量发布时机错误:当前
thread_A先执行sem_post(&sem)再执行malloc分配数组,会导致function_B拿到信号量时array还未完成初始化,直接访问触发野指针崩溃。 - 信号量计数逻辑错误:信号量初始值为0,
thread_A每次循环都执行一次post,如果function_B没有及时消费信号量,信号量计数会累计到大于1,下次循环还未执行malloc时function_B就能成功获取信号量,同样会访问非法内存。 - 数组释放前无同步逻辑:
thread_A休眠2秒后直接执行free(array),没有判断当前是否有线程正在写入数组,会触发释放后使用(UAF)的内存错误。 - 共享变量无并发保护:
array、position都是多线程共享的全局变量,没有加锁保护的情况下并发访问会出现竞争条件,比如position计数异常、array指针读取到半初始化的值。 sem_trywait返回值判断逻辑倒置:sem_trywait成功获取信号量时返回值为0,失败返回非0,当前代码if(sem_trywait(&sem))的判断逻辑会导致获取信号量成功时不执行写入,获取失败反而进入写入分支,完全不符合预期。
修复示例代码
全局变量与初始化
#include <pthread.h> #include <semaphore.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> int *array = NULL; int position = 0; sem_t sem; // 新增互斥锁保护array、position等共享变量 pthread_mutex_t array_mutex = PTHREAD_MUTEX_INITIALIZER; // 主函数初始化逻辑 int main() { // 信号量初始值仍为0 sem_init(&sem, 0, 0); // 后续线程创建逻辑省略 return 0; }
thread_A 实现修复
static void *thread_A(void *p_vp_arg) { while (1) { pthread_mutex_lock(&array_mutex); array = malloc(1024 * sizeof(int)); position = 0; // 每次分配新数组后重置写入位置 pthread_mutex_unlock(&array_mutex); sem_post(&sem); // 数组分配完成后再发布信号量,通知可写入 /* 原有业务逻辑 */ sleep(2); // 释放前清空未消费的信号量,避免下次循环前被错误获取 sem_trywait(&sem); pthread_mutex_lock(&array_mutex); free(array); array = NULL; // 释放后置空,避免野指针访问 pthread_mutex_unlock(&array_mutex); } }
function_B 实现修复
static void function_B(int variable){ // 正确判断信号量获取成功的返回值 if(sem_trywait(&sem) == 0){ pthread_mutex_lock(&array_mutex); // 双重校验避免极端情况下数组已被释放、写入越界 if(array != NULL && position < 1024){ printf("I can write into the array\n"); array[position] = variable; position += 1; } pthread_mutex_unlock(&array_mutex); // 如果需要支持数组有效期内多次写入,此处新增 sem_post(&sem) 归还信号量即可 } }
可选优化方案
如果业务需要在数组的2秒有效期内支持任意次数的写入,可以将信号量替换为读写锁:数组分配完成后加读锁,释放数组前解读锁,写入操作尝试加读锁,成功即可执行写入,逻辑会更简洁清晰。
内容的提问来源于stack exchange,提问作者Report Feedback
相关产品推荐
相关产品推荐

