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

C语言IPC队列动态消息问题:msgsnd/msgrcv错误及跨平台打印异常

问题分析与解决方案

核心问题概述

  • IPC消息队列的msgsnd/msgrcv调用存在错误
  • 跨平台输出不一致:MacOS下msgsnd前缓冲区内容正常,Ubuntu下打印部分内容后出现乱码

问题定位与修复

1. IPC消息队列调用错误

消息队列调用错误通常集中在结构体定义和参数传递上:

  • 消息结构体必须以long mtype作为第一个成员,发送与接收时需保证类型匹配
  • msgsnd的第三个参数是消息正文的长度(不包含mtype字段),常见错误是传入整个结构体的长度
  • msgrcv的第四个参数是接收正文的最大长度,需与发送端一致,同时要指定正确的消息类型(msgtyp参数)

正确调用示例:

// 标准消息结构体定义
typedef struct {
    long mtype;
    char mtext[BUFSIZ];
} msgbuf;

// 发送消息
msgbuf buf;
buf.mtype = 1; // 自定义消息类型,接收端需对应
strncpy(buf.mtext, content, BUFSIZ-1);
buf.mtext[BUFSIZ-1] = '\0';
// 传入正文长度(含终止符)
msgsnd(msgid, &buf, strlen(buf.mtext)+1, 0);

// 接收消息
// 仅接收类型为1的消息,正文最大长度为BUFSIZ
msgrcv(msgid, &buf, BUFSIZ, 1, 0);

2. Ubuntu下的乱码问题

乱码主要由以下因素导致:

  • 缓冲区未终止:读取文件内容时未强制添加\0,Ubuntu内存布局差异会导致读取到垃圾数据
  • 线程同步缺失:生产者写入队列与消费者读取时无同步机制,导致缓冲区被覆盖
  • 文件编码差异:若文件非UTF-8编码,Ubuntu终端解码会出现乱码

修复建议:

  • 读取文件内容后,强制在缓冲区末尾添加\0,确保字符串终止
  • 添加互斥锁与信号量实现生产者-消费者同步,避免数据竞争
  • 统一文件编码为UTF-8

同步代码示例:

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
sem_t sem;
sem_init(&sem, 0, 0);

// 生产者端
pthread_mutex_lock(&mutex);
// 队列写入操作
pthread_mutex_unlock(&mutex);
sem_post(&sem);

// 消费者端
sem_wait(&sem);
pthread_mutex_lock(&mutex);
// 队列读取操作
pthread_mutex_unlock(&mutex);

完整修复后的代码

#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <string.h>
#include <sys/msg.h>
#include <pthread.h>
#include <semaphore.h>

#define BUFSIZ 1024
#define MSG_TYPE 1

typedef struct {
    long mtype;
    char mtext[BUFSIZ];
} msgbuf;

int msgid;
pthread_mutex_t mutex;
sem_t sem;

// 消费者线程函数
void *consumer(void *arg) {
    msgbuf buf;
    while(1) {
        sem_wait(&sem);
        pthread_mutex_lock(&mutex);
        if(msgrcv(msgid, &buf, BUFSIZ, MSG_TYPE, 0) == -1) {
            perror("msgrcv");
            pthread_mutex_unlock(&mutex);
            break;
        }
        pthread_mutex_unlock(&mutex);
        printf("%s", buf.mtext);
        // 检测结束标记(空字符串)
        if(strlen(buf.mtext) == 0) break;
    }
    return NULL;
}

// 遍历文件夹并处理符合模式的文件
void process_folder(const char *folder, const char *pattern) {
    DIR *dir = opendir(folder);
    if(!dir) {
        perror("opendir");
        return;
    }
    struct dirent *entry;
    msgbuf buf;
    buf.mtype = MSG_TYPE;
    char path[BUFSIZ];
    FILE *fp;
    size_t n;

    while((entry = readdir(dir)) != NULL) {
        if(strstr(entry->d_name, pattern) != NULL) {
            snprintf(path, BUFSIZ, "%s/%s", folder, entry->d_name);
            fp = fopen(path, "r");
            if(!fp) {
                perror("fopen");
                continue;
            }
            while((n = fread(buf.mtext, 1, BUFSIZ-1, fp)) > 0) {
                buf.mtext[n] = '\0'; // 强制添加字符串终止符
                pthread_mutex_lock(&mutex);
                if(msgsnd(msgid, &buf, strlen(buf.mtext)+1, 0) == -1) {
                    perror("msgsnd");
                    pthread_mutex_unlock(&mutex);
                    fclose(fp);
                    closedir(dir);
                    return;
                }
                pthread_mutex_unlock(&mutex);
                sem_post(&sem);
            }
            fclose(fp);
        }
    }
    // 发送结束标记
    memset(buf.mtext, 0, BUFSIZ);
    pthread_mutex_lock(&mutex);
    msgsnd(msgid, &buf, 1, 0);
    pthread_mutex_unlock(&mutex);
    sem_post(&sem);
    closedir(dir);
}

int main(int argc, char *argv[]) {
    if(argc != 3) {
        fprintf(stderr, "Usage: %s <folder> <pattern>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    // 创建消息队列
    key_t key = ftok(".", 'M');
    if(key == -1) {
        perror("ftok");
        exit(EXIT_FAILURE);
    }
    msgid = msgget(key, IPC_CREAT | 0666);
    if(msgid == -1) {
        perror("msgget");
        exit(EXIT_FAILURE);
    }

    // 初始化同步工具
    pthread_mutex_init(&mutex, NULL);
    sem_init(&sem, 0, 0);

    // 创建消费者线程
    pthread_t tid;
    if(pthread_create(&tid, NULL, consumer, NULL) != 0) {
        perror("pthread_create");
        exit(EXIT_FAILURE);
    }

    // 处理目标文件夹
    process_folder(argv[1], argv[2]);

    // 等待消费者线程结束
    pthread_join(tid, NULL);

    // 清理资源
    msgctl(msgid, IPC_RMID, NULL);
    pthread_mutex_destroy(&mutex);
    sem_destroy(&sem);

    return EXIT_SUCCESS;
}

编译与运行命令

gcc program.c -o program -pthread
./program my_folder score

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 12:30:30