You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 14:36:08