C语言Win32多线程同步场景下全局队列修改失效问题咨询
问题原因
1. 结构体值传递导致修改不生效(核心原因)
C语言中结构体作为参数传递时默认是值拷贝,你当前enque、deque函数的入参是struct queue类型,调用时传入全局q1/q2,函数内部操作的是全局队列的临时副本,所有对q.end、q.size、q.arr_pac的修改都不会作用到全局队列上。函数执行结束后临时副本销毁,全局队列的成员值始终保持初始状态,这就是你在queueprocess中打印q1值全为0的根本原因。
2. 多线程并发访问竞态问题
即使修复了值传递问题,你的代码依然存在多线程安全问题:三个线程会同时读写q1/q2的公共成员(start/end/size),没有同步机制的情况下会出现数据读写不一致、队列状态错乱的问题,比如入队线程刚判断队列未满,出队线程已经把队列删空,最终导致越界访问等异常。
解决方案
1. 修复结构体传参逻辑
将所有操作队列的函数入参改为结构体指针,直接修改全局队列的内存:
修改enque函数
// 入参改为指针 int enque(struct queue* q){ if (q->size < 10) { struct packet temp ; temp.start_time = time(NULL); temp.val = 1; q->arr_pac[q->end] = temp; q->end = q->end +1; q->size = q->end - q->start; return q->size; } else{ return -1; } }
修改deque函数
// 入参改为指针 struct packet deque(struct queue* q) { struct packet temp ; if(q->size >0){ temp=q->arr_pac[q->start]; temp.service_time = difftime(time(NULL),temp.start_time); q->start=q->start +1; q->size = q->end - q->start; return temp; } else{ temp.service_time=0; return temp; } }
调整调用逻辑
所有调用enque/deque的地方改为传地址:
// 原来的enque(q1)改为 enque(&q1); // 原来的deque(q)改为 deque(&q);
同时process1、process2结构体中存储队列的成员也要改为指针类型,避免参数传递时再次拷贝队列副本。
2. 增加Win32线程同步机制
Windows平台针对同进程内的线程同步,推荐使用性能更高的CRITICAL_SECTION(临界区),使用步骤如下:
定义全局锁
struct queue q1 ; struct queue q2; // 新增两个临界区,分别对应两个队列的访问锁 CRITICAL_SECTION cs_q1, cs_q2;
初始化与销毁锁
在main函数最开始初始化临界区,所有线程执行结束后销毁临界区:
int main(int argc, char * argv[]) { // 初始化临界区 InitializeCriticalSection(&cs_q1); InitializeCriticalSection(&cs_q2); // 初始化全局队列 q1 = initialiseQueue(); q2 = initialiseQueue(); // 原有线程创建逻辑 HANDLE hThrds[3]; DWORD thread1,thread2,thread3; hThrds[2]=CreateThread(NULL,0, threadone, NULL,0,&thread1); hThrds[0]=CreateThread(NULL,0, threadtwo, NULL,0,&thread2); hThrds[1]=CreateThread(NULL,0, threadthree, NULL,0,&thread3); WaitForMultipleObjects(3, hThrds,TRUE, INFINITE); // 销毁临界区 DeleteCriticalSection(&cs_q1); DeleteCriticalSection(&cs_q2); return 0; }
访问队列前后加解锁
所有操作q1的代码前后加锁解锁,操作q2同理:
// 操作q1前加锁 EnterCriticalSection(&cs_q1); // 执行操作:入队/出队/读取队列成员 int res = enque(&q1); // 操作完成后解锁 LeaveCriticalSection(&cs_q1);
3. 其他已知问题修复
- 打印浮点数时不要传变量地址,直接传变量值:
// 错误写法:printf("Blocking Probability is : %f",&blockPro); // 正确写法: printf("Blocking Probability is : %f", blockPro); - Windows平台
Sleep函数单位为毫秒,你生成的间隔是秒级浮点数,需要转换单位:// 错误写法:sleep(interval); // 正确写法: Sleep(interval * 1000);
内容的提问来源于stack exchange,提问作者Ram
相关产品推荐
相关产品推荐

