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

C语言进程间消息队列程序异常:文件内容未完全打印排查

问题:IPC消息队列程序未打印全部文件内容

我正在用C语言编写基于进程间通信(IPC)消息队列的程序,需求如下:

  • 从命令行接收至少一个文件,创建与文件数量相同的子进程;
  • 子进程将文件内容发送至Receiver进程,由该进程打印收到的消息。

但程序运行时出现问题:即便子进程已发送消息,文件内容仍未全部打印。以下是我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/stat.h>

#define DIM_MSG 1024

#define TYPE_W 2

typedef struct
{
    long mtype;
    char eof;
    char mtext[DIM_MSG];
} msg;

void child_r(int coda, const char *file)
{

    FILE *r_stream;
    if ((r_stream = fopen(file, "r")) == NULL)
    {
        perror("errore apertura file");
        exit(1);
    }

    printf("%s:\n",file);

    msg messaggio;

    while (fgets(messaggio.mtext, DIM_MSG, r_stream) != NULL)
    {
        messaggio.mtype = TYPE_W;
        messaggio.eof = 0;
        if (msgsnd(coda, &messaggio, sizeof(msg) - sizeof(long), 0) == -1)
        {
            perror("msgsnd");
            exit(1);
        }
        printf("\tMessage send: %s", messaggio.mtext);
    }

    strcpy(messaggio.mtext, "quit");
    messaggio.eof = 1;
    messaggio.mtype = TYPE_W;
    if (msgsnd(coda, &messaggio, sizeof(msg) - sizeof(long), 0) == -1)
    {
        perror("msgsnd");
        exit(1);
    }

    fclose(r_stream);
    exit(0);
}

void child_f(int coda, int child_count)
{
    msg messaggio;
    int eof_received = 0;

    printf("\nReceiver\n");

    do
    {
        if (msgrcv(coda, &messaggio, sizeof(msg) - sizeof(long), TYPE_W, 0) == -1)
        {
            perror("msgrcv");
            exit(1);
        }

        if (strcmp(messaggio.mtext, "quit") != 0)
        {
            printf("\tMessage rcv: %s ", messaggio.mtext);
        }
        else
        {
            eof_received++;
        }

    } while (eof_received < child_count);

    exit(0);
}

int main(int argc, char const *argv[])
{
    char *file_name = NULL;
    struct stat sb;
    int child=0;

    int ds_coda;

    if(argc < 2)
    {
        fprintf(stderr,"Utilizzo %s <file-1> <file-2> <file-n>....\n",argv[0]);
        exit(1);
    }

    if((ds_coda=msgget(IPC_PRIVATE,IPC_CREAT|IPC_EXCL|0600))==-1)
    {
        perror("coda");
        exit(1);
    }

    /* analizza la command-line */
    for (int i = 1; i < argc; i++) {
            if ((stat(argv[i], &sb) == 0) && (S_ISREG(sb.st_mode)))
            {
                file_name = (char*)argv[i];
                child++;
                if(fork()==0)
                {
                    child_r(ds_coda, file_name);
                }
            }
            else {
                perror(argv[i]);
                exit(1);
            }
    }
        
    if(child==0)
    {
        fprintf(stderr,"Parametri non validi!\n");
        exit(1);
    }

    if(fork() == 0)
    {
        // child_w
        child_f(ds_coda, child);
    }

    // 等待所有子进程退出
    for(int i=0; i < child + 1; i++)
    {
        wait(NULL);
    }

    msgctl(ds_coda, IPC_RMID, NULL);
   
    return 0;
}

问题分析与修复说明

  1. Receiver提前退出:原代码主进程仅调用一次wait(NULL),Receiver进程退出后主进程立刻销毁消息队列,导致其他子进程的消息未被处理。修复后主进程循环等待所有子进程(文件子进程+Receiver)退出。
  2. EOF标记逻辑错误:原Receiver收到第一个EOF消息就退出,无法处理其他文件子进程的内容。修复后Receiver统计收到的EOF数量,等于文件子进程数时才退出。
  3. 参数判断错误:原代码argc<1逻辑错误,命令行至少需要一个文件参数,修正为argc<2。
  4. 移除不可靠的sleep(1):靠sleep实现进程同步不可靠,修复后直接启动Receiver,无需等待。

内容的提问来源于stack exchange,提问作者Valentino Fabris Valenti

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 20:02:20