管道和叉子 - scanf只读取一个字符

时间:2014-05-19 16:43:10

标签: c linux fork pipe scanf

我有一个任务是写3个与管道连接在一起的过程。第一个应该从用户读取输入,第二个应该从第1个读取并且使字母大写,3个应该从第2个读取并打印结果。问题是scanf只读取第一个按下的字符,然后程序结束。我做错了什么?我试图发送硬编码的字符串,它工作得很好。

#include <unistd.h>
#include <stdio.h>
#include <ctype.h>
#define ODCZYT 0
#define ZAPIS 1

int main(){
        char readbuffer[80];
        char tempbuffer[80];
        char printbuffer[80];
        int i=0;

        int potok[2];
        int potok2[2];
        pid_t pid_A, pid_B, pid_C;

        pipe( potok );
        pipe( potok2);
        puts( "fork" );
        if(!(pid_A = fork()) )
        {

                puts("Podaj string:");
                close(potok[ODCZYT]);
                close(potok2[ODCZYT]);
                close(potok2[ZAPIS]);
                scanf( "%s", readbuffer )
                write(potok[ZAPIS],readbuffer, sizeof(readbuffer));    
                close(potok[ZAPIS]);
        }
        if(!(pid_B = fork()) )
        {
                close( potok[ZAPIS] );
                close(potok2[ODCZYT]);
                read( potok[ODCZYT], tempbuffer, sizeof(tempbuffer));
                close(potok[ODCZYT]);
                while(tempbuffer[i]){
                        tempbuffer[i]=toupper(tempbuffer[i]);          
                        i++;                   
                }
                write(potok2[ZAPIS],tempbuffer, sizeof(tempbuffer));
                close(potok2[ZAPIS]);
        }
        if( !(pid_C = fork()) ) {

                close(potok[ODCZYT]);
                close(potok[ZAPIS]);
                close(potok2[ZAPIS]);
                read( potok2[ODCZYT], printbuffer, sizeof(printbuffer));
                puts(printbuffer);
                close(potok2[ODCZYT]);

        }
        return 0;
}

2 个答案:

答案 0 :(得分:1)

问题代码可能会做出更多预期。它不是创建3个进程,而是创建7个进程,不包括main()进程,实际上是8个进程。

线程[main()]确实创建了线程[A],[B]和[C]。

线程[A]在第一个if块内完成工作,然后继续创建线程[B1]和[C1]。

线程[B]在第二个if块内完成工作,然后继续创建线程[C2]。

线程[B1]在第二个if块内完成工作,然后继续创建线程[C3]。

要查看,总线程包括[main()],[A],[B],[C],[B1],[C1],[C2]&amp; [C3]。

这不是问题描述所表明的。


要修复代码,请在每个'if'块的底部放置一个return(0)语句,这将导致每个线程只执行其中'if'块中的任务。


一个小小的修正......改变:

scanf( "%s", readbuffer )

为:

scanf( "%s", readbuffer );  //<-- Add semicolon 

使用内容

创建test.txt文件
uppercase

然后运行程序:

> ./test < test.txt

打印'UPPERCASE'的结果


为什么scanf()仅在从键盘输入时读取一个字符,但在从文件读取时有效?

问题是线程同步问题。线程[main()]终止,shell程序(即:Bash等)试图重新获得控制权;但是线程[A]的scanf()需要一个事件(例如传入的字符)才能意识到它是时候终止(和终止)了。一旦按下一个键,线程[A]就会吞噬它,但是线程[A]会立即终止,而不会从键盘处理该字符。 scanf()永远不会真正返回!一旦线程[A]终止,shell程序(即:Bash等)就会重新获得对键盘的控制权。

如何解决这个问题?

让线程[main()]等待线程[C]终止。更改程序结束,添加waitpid()电话:

   waitpid(pid_C, NULL, 0);

   return(0);

(当然,为了引用waitpid(),您必须添加相应的.h文件。)


可在以下位置找到固定代码:http://www.mahonri.info/SO/23743011_pipes-and-fork-scanf-is-reading-only-one-character.c        }

答案 1 :(得分:0)

read()和write()不保证返回您要求的所有字节。检查read()和write()调用的返回值,以查看实际读取和写入的字符数。您可能需要循环才能获得所有这些内容。此外,我没有运行您的代码段,但您没有对父进程执行任何操作。您需要在每个条件结束时退出父级,以防止它运行下一个部分,这可能会产生不良后果。