我正在编写一个由2个进程组成的程序。父级通过stdin读取数据,然后通过管道将其发送给子级。我正在使用fgets()和fputs()来编写和读取数据。
问题是在某些情况下,子进程的fgets()调用似乎被阻止。这些是:
我怀疑这个问题与这些字符串末尾的EOF或/ 0有关,但我无法确定问题。任何帮助将不胜感激。
我正在使用消息队列作为同步手段。我也知道这段代码没有清理。这是:
#define KEY5 7626
struct pidbuf
{
long mtype;
int mtext;
} msgpid;
int main(){
sleep(5);
int mqpid;
FILE * strumien;
int fd[2];
if (pipe(fd)== -1){
perror("Create pipe error");
exit(1);}
int buf_len = 128;
msgpid.mtext=0;
int size1=sizeof(struct pidbuf)-sizeof(long);
if((mqpid = msgget(KEY5, 0666 | IPC_CREAT))==-1){
return(-1);
}
char data[buf_len];
if(fork()!=0){
close(fd[0]);
strumien=fdopen(fd[1],"w");
while (fgets(data,buf_len,stdin) != NULL ) {
printf("1:\n%s\n",data);
fputs(data,strumien);
fflush(strumien);
msgpid.mtype=2;
if(msgsnd(mqpid,&msgpid,size1,0)==-1){perror("msgsnd failed: 1");}
msgrcv(mqpid,&msgpid,size1, 1, 0);
}
if(feof(stdin)!=0) printf("\nEnd of file\n");
}
else{
close(fd[1]);
strumien=fdopen(fd[0],"r");
msgrcv(mqpid,&msgpid,size1, 2, 0);
while(fgets(data,buf_len,strumien)!=NULL){
printf("2:\n%s\n\n",data);
msgpid.mtype=1;
if(msgsnd(mqpid,&msgpid,size1,0)==-1){perror("msgsnd failed: 1");}
msgrcv(mqpid,&msgpid,size1, 2, 0);
}
}
return 0;
}
答案 0 :(得分:1)
不太令人惊讶 - 父进程为读取的文件的每一行发送一条类型为2的消息,并在写入每一行后等待类型1的消息。另一方面,孩子是不同的 - 当它发送类型1并在每行之后等待类型2时,它也会在读取第一行之前等待类型2。
因此父母将发送N类型2消息,而孩子将等待N行1文件的N + 1类型2消息。这意味着在父母完成并退出后,孩子将被阻止等待最后一条永远不会到来的消息。
明显的解决方法是让父母发送一条额外的消息 - 可能是在循环之后,具体取决于你想要实现的目标。
对于/dev/urandom
(或任何二进制输入),当输入包含NUL字节时,您还有一个问题。然后,父级中的fgets
将很高兴地读取NUL并继续将其传递给换行符(或缓冲区已满),但是下面的fputs
只会写入(并且不包括)NUL 。因此,一些数据将丢失,孩子将继续阅读以查找换行符,并在fgets
中阻止该孩子,并在发送下一行之前将其阻止在msgrcv
。
由于fgets
/ fputs
旨在处理文本而非二进制数据,因此没有简单的方法来解决此问题。您可以改为使用fread
或getline
和fwrite
,它们会为您提供读取/写入数据量的明确长度,因此您可以知道它何时读取了非NUL这些数据的结尾。