Linux Posix消息队列问题:父进程无法打印子进程发送的素数
问题排查与修复方案
1. 格式符不匹配导致素数筛选失效
代码中使用 %ld 读取 int64_t 类型变量,但 %ld 对应**long int**,而 int64_t 的标准格式符应为 %lld(或引入 <inttypes.h> 头文件后使用 PRId64 宏更规范)。格式符不匹配会导致读取的数值错误,进而让 isPrime 函数无法正确识别素数,最终没有任何消息发送到队列,父进程自然不会打印内容。
修复:
// 先引入头文件 #include <inttypes.h> // 替换读取时的格式符 while (fscanf(file, "%" PRId64, &number) == 1) {
或直接使用 %lld(适用于多数64位系统):
while (fscanf(file, "%lld", &number) == 1) {
2. 父进程消息处理逻辑错误
父进程依赖 mq_getattr 轮询队列消息数的逻辑存在两个致命问题:
- 队列空时,父进程会持续空转,不会阻塞等待子进程发送消息;
- 所有子进程退出后,父进程会无限循环(
mq_getattr始终返回0),无法正常终止。
正确做法是先等待所有子进程退出,再阻塞读取队列剩余消息:
// 记录子进程PID pid_t child_pids[N]; for (int i = 0; i < N; i++) { pid_t pid = fork(); if (pid < 0) { perror("Fork failed"); exit(EXIT_FAILURE); } else if (pid == 0) { // 子进程原有逻辑不变 // ... } else { child_pids[i] = pid; } } // 等待所有子进程退出 for (int i = 0; i < N; i++) { waitpid(child_pids[i], NULL, 0); } // 读取队列中所有剩余消息 int64_t number; ssize_t recv_len; while ((recv_len = mq_receive(mq, (void *)&number, sizeof(number), NULL)) != -1) { if (recv_len == sizeof(number)) { printf("%lld\n", number); // 注意格式符匹配 } } // 验证退出原因是否为队列空 if (errno == ENOMSG) { printf("所有消息处理完毕\n"); } else { perror("mq_receive failed"); }
3. 缺少系统调用错误检查
代码多处未检查系统调用返回值,无法及时发现问题:
- 检查
mq_open是否成功:
mq = mq_open(MQ_NAME, O_CREAT | O_RDWR, 0644, &mq_attributes); if (mq == (mqd_t)-1) { perror("mq_open failed"); exit(EXIT_FAILURE); }
- 检查
mq_send是否成功:
if (mq_send(mq, (void *)&number, sizeof(number), 0) == -1) { perror("mq_send failed"); // 可根据场景选择退出或重试 }
4. 消息队列容量限制
确保 M(mq_maxmsg)的取值不超过系统限制,可通过 /proc/sys/fs/mqueue/msg_max 查看系统默认上限,避免因队列容量过小导致消息发送阻塞或失败。
内容的提问来源于stack exchange,提问作者DenizTuna
相关产品推荐
相关产品推荐

