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

多进程C语言锦标赛程序日志重复输出异常排查求助

问题描述

我编写了一个模拟完整锦标赛的C程序,需将结果写入日志文件。每个赛事阶段的每场比赛由单独子进程(通过fork创建)处理。父进程等待所有子进程结束后,通过消息队列获取结果并写入日志,但实际日志多次重复输出八分之一决赛等赛事段内容(如重复8次八分之一决赛结尾标识),与预期的按阶段依次输出不符。


核心代码

/**data preparation and stuff**/

for(int i = 0; i < nbMatch; i++){

    int pid = fork();
    if(pid == -1){

        perror("Error occured while forking\n"); 
        return 1;
    }else if(pid == 0){

        srand(getpid());
        Team t;
        if(mode == 2){

            P(mutId);
            t = match(tabMatch[i],mode,fx);
            V(mutId);
        }
        else{

            t = match(tabMatch[i],mode,fx);
        }
        Message buf;
        if((msgsend(msgid, buf, teamName(t), strlen(teamName(t)))) == -1){

            perror("Error occured while putting a message in the queue, shutting down\n");
            return 4;
        }
        exit(0);
    }
}
while((wpid = wait(&status)) > 0);//waiting for every children processes to die.
Message buffer;
char *res;
for(int i = 0; i < nbMatch; i++){
    res = msgrecv(msgid,buffer);
    Team t = getTeam(b,res);
    Team the = getOponent(tabMatch, (*t).name, nbMatch);
    fprintf(fx,"Match numéro %d du %d de finale: Perdant : %s , Gagnant : %s\n",i+1,
    nbMatch,
    t->name,
    the->name);
    b = suppTeam(b,t);
}
fprintf(fx,"---FIN DU %d DE FINALE---\n", nbMatch);
nbMatch = nbMatch / 2;
if(nbMatch == 0){
    mutfree(mutId);
    finBracket = 1;
    printf("\33[1;32mThe grand winner is : %s \33[0m\n",teamName(b->team));
}else{
    printf("\nEnd of the segment\n\n\n");
}

/*Other stuff*/

期望输出

Match numéro 1 du 8 de finale: Perdant : Orange , Gagnant : famas viseur holo chargeur grande capacité
Match numéro 2 du 8 de finale: Perdant : Condeflan , Gagnant : Quiperd
Match numéro 3 du 8 de finale: Perdant : Sertgille , Gagnant : Pau
Match numéro 4 du 8 de finale: Perdant : ekip , Gagnant : griffondor
Match numéro 5 du 8 de finale: Perdant : BoisBubulle , Gagnant : denis
Match numéro 6 du 8 de finale: Perdant : Antredonc , Gagnant : Nan
Match numéro 7 du 8 de finale: Perdant : Free , Gagnant : L'ile
Match numéro 8 du 8 de finale: Perdant : FC bretagne , Gagnant : Brusxsscsel
---FIN DU 8 DE FINALE---
Match numéro 1 du 4 de finale: Perdant : Pau , Gagnant : griffondor
Match numéro 2 du 4 de finale: Perdant : Brusxsscsel , Gagnant : Quiperd
Match numéro 3 du 4 de finale: Perdant : L'ile , Gagnant : denis
Match numéro 4 du 4 de finale: Perdant : Nan , Gagnant : famas viseur holo chargeur grande capacité
---FIN DU 4 DE FINALE---
[...]---FIN DU 2 DE FINALE---

实际输出

Match numéro 1 du 8 de finale: Perdant : Orange , Gagnant : famas viseur holo chargeur grande capacité
Match numéro 2 du 8 de finale: Perdant : Condeflan , Gagnant : Quiperd
Match numéro 3 du 8 de finale: Perdant : Sertgille , Gagnant : Pau
Match numéro 4 du 8 de finale: Perdant : ekip , Gagnant : griffondor
Match numéro 5 du 8 de finale: Perdant : BoisBubulle , Gagnant : denis
Match numéro 6 du 8 de finale: Perdant : Antredonc , Gagnant : Nan
Match numéro 7 du 8 de finale: Perdant : Free , Gagnant : L'ile
Match numéro 8 du 8 de finale: Perdant : FC bretagne , Gagnant : Brusxsscsel
---FIN DU 8 DE FINALE---
Match numéro 1 du 4 de finale: Perdant : Pau , Gagnant : griffondor
Match numéro 2 du 4 de finale: Perdant : Brusxsscsel` , Gagnant : Quiperd`
Match numéro 3 du 4 de finale: Perdant : L'ile` , Gagnant : denis
Match numéro 4 du 4 de finale: Perdant : Nan` , Gagnant : famas viseur holo chargeur grande capacité
---FIN DU 4 DE FINALE---
Match numéro 1 du 8 de finale: Perdant : Orange` , Gagnant : famas viseur holo chargeur grande capacité
Match numéro 2 du 8 de finale: Perdant : Condeflan` , Gagnant : Quiperd`
Match numéro 3 du 8 de finale: Perdant : Sertgille , Gagnant : Pau
Match numéro 4 du 8 de finale: Perdant : ekip , Gagnant : griffondor
Match numéro 5 du 8 de finale: Perdant : BoisBubulle` , Gagnant : denis
Match numéro 6 du 8 de finale: Perdant : Antredonc` , Gagnant : Nan`
Match numéro 7 du 8 de finale: Perdant : Free` , Gagnant : L'ile`
Match numéro 8 du 8 de finale: Perdant : FC bretagne , Gagnant : Brusxsscsel`
---FIN DU 8 DE FINALE---
Match numéro 1 du 4 de finale: Perdant : Pau , Gagnant : griffondor
Match numéro 2 du 4 de finale: Perdant : Brusxsscsel` , Gagnant : Quiperd`
Match numéro 3 du 4 de finale: Perdant : L'ile` , Gagnant : denis
Match numéro 4 du 4 de finale: Perdant : Nan` , Gagnant : famas viseur holo chargeur grande capacité
---FIN DU 4 DE FINALE---
[till the eof...]

问题原因及解决方案

1. 消息队列结构未正确初始化,导致消息类型混乱

System V消息队列要求消息结构的第一个成员必须是long mtype(消息类型),用于区分不同消息。你的代码中Message buf是未初始化的自动变量,栈上的垃圾值会导致mtype随机,父进程读取时会混入旧阶段的残留消息或乱序消息,进而重复输出旧阶段内容。

解决办法:

  • 定义规范的消息结构:
    typedef struct {
        long mtype; // 必须是第一个成员
        char mtext[256]; // 存储队伍名称,预留足够空间
    } Message;
    
  • 子进程发送消息时初始化mtype为固定值(比如1,统一标识比赛结果消息),并确保字符串终止:
    Message buf;
    buf.mtype = 1;
    strncpy(buf.mtext, teamName(t), sizeof(buf.mtext)-1);
    buf.mtext[sizeof(buf.mtext)-1] = '\0'; // 强制添加终止符
    if(msgsnd(msgid, &buf, strlen(buf.mtext)+1, 0) == -1) {
        perror("msgsnd failed");
        exit(4);
    }
    
  • 父进程接收时指定读取mtype=1的消息:
    res = msgrecv(msgid, &buffer, sizeof(buffer.mtext), 1);
    

2. 字符串未正确终止,输出乱码

实际输出中的多余符号,是因为teamName(t)返回的字符串没有\0终止符,导致strlen`计算错误,写入消息队列时混入栈垃圾字符。

解决办法:

  • 确保teamName(t)返回的字符串自带终止符,或者手动复制时添加:
    char team_name[256];
    strncpy(team_name, teamName(t), sizeof(team_name)-1);
    team_name[sizeof(team_name)-1] = '\0';
    

3. 消息队列未在阶段结束后清理

如果某阶段的消息未被完全读取,残留消息会被下一阶段父进程读取,导致重复输出旧内容。

解决办法:

  • 每个阶段结束后,清空消息队列剩余内容:
    Message temp_buf;
    // 非阻塞读取剩余消息,直到队列为空
    while(msgrcv(msgid, &temp_buf, sizeof(temp_buf.mtext), 1, IPC_NOWAIT) != -1) {}
    

4. 锦标赛阶段推进逻辑可能出错

检查suppTeam(b,t)和nbMatch的更新逻辑,若b未正确更新,会导致nbMatch未被正确减半,大循环重复执行同一阶段。


内容的提问来源于stack exchange,提问作者Djolalo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 13:22:00