【问题标题】:Pipes and fork - scanf is reading only one character管道和叉子 - scanf 只读取一个字符
【发布时间】:2014-05-19 16:43:10
【问题描述】:

我的任务是编写 3 个通过管道连接在一起的进程。第一个应该读取用户的输入,第二个应该从第一个读取并将字母变为大写,第三个应该从第二个读取并打印结果。问题是 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;
}

【问题讨论】:

  • 您有多个小错误,其中一些已在下面得到解答。首先,您必须学会检查您的返回码。何时以及是否做很多事情会变得更加清晰。

标签: c linux fork pipe scanf


【解决方案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]和[C3]。

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


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


还有一个小的修正……更改:

scanf( "%s", readbuffer )

到:

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

使用内容创建一个test.txt 文件:

uppercase

然后运行程序:

> ./test < test.txt

导致打印“大写”


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

问题是线程同步问题。 Thread[main()] 终止,shell 程序(即:Bash 等)试图重新获得控制权;但是 thread[A] 的 scanf() 需要一个事件(例如传入的字符)才能意识到是时候终止(和终止)了。只要按下一个键,thread[A] 就会将其吞噬,但随后 thread[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 }

【讨论】:

    【解决方案2】:

    read() 和 write() 不能保证返回您要求的所有字节。检查您的 read() 和 write() 调用的返回值,以查看实际读取和写入的字符数。您可能需要循环获取所有这些。另外,我没有运行你的 sn-p,但你没有对父进程做任何事情。您需要在每个条件结束时退出父项,以防止它运行下一部分,这可能会产生不良后果。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-08-16
      • 1970-01-01
      • 2022-11-24
      • 1970-01-01
      • 2018-05-26
      • 2018-05-23
      • 1970-01-01
      • 2017-07-07
      相关资源
      最近更新 更多