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; }
问题分析与修复说明
- Receiver提前退出:原代码主进程仅调用一次
wait(NULL),Receiver进程退出后主进程立刻销毁消息队列,导致其他子进程的消息未被处理。修复后主进程循环等待所有子进程(文件子进程+Receiver)退出。 - EOF标记逻辑错误:原Receiver收到第一个EOF消息就退出,无法处理其他文件子进程的内容。修复后Receiver统计收到的EOF数量,等于文件子进程数时才退出。
- 参数判断错误:原代码
argc<1逻辑错误,命令行至少需要一个文件参数,修正为argc<2。 - 移除不可靠的
sleep(1):靠sleep实现进程同步不可靠,修复后直接启动Receiver,无需等待。
内容的提问来源于stack exchange,提问作者Valentino Fabris Valenti
相关产品推荐
相关产品推荐

