cat 破坏程序,手动 stdin 输入不会
cat breaks the program, manual stdin input doesn't
我有这个小程序:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main() {
int orig = 1;
for (int i = 0; (i != 3) && orig; ++i) {
orig = orig && fork();
}
if (orig) {
for (int i = 0; i != 3; ++i) {
wait(NULL);
}
} else {
int num;
scanf("%8d", &num);
printf("%d\n", num*num);
}
}
它应该简单地对从 stdin
中读取的三个数字进行平方。如果我自己输入数字,它会起作用:
akiiino$ ./out.out
12345678
12345678
12345678
260846532
260846532
260846532
但是如果我将 cat 用于相同的目的,它不会按预期工作:
akiiino$ cat in.txt
12345678
12345678
12345678
akiiino$ cat in.txt | ./out.out
260846532
0
0
这种奇怪行为背后的原因是什么,是否可以修复?我一直认为 cat
编辑文件与将它们输入 stdin
.
没有什么不同
@Some programmer dude 已经说过,问题出在 fork
命令上。
如果您尝试 ./out.out < in.txt
,它应该可以正常工作。
不同之处在于,当您手动键入 3 个数字时,您是从终端读取并且低级读取在换行处终止。让我们看看幕后发生了什么。
手动输入:
- 3 child 已启动并正在等待输入
- 您键入一个数字并换行
- 基础
read
调用被换行符终止,因为您从终端读取
- 第一个 child(获得读取的)
scanf
调用解码输入并进行处理
好的,我们对另外两个 childs
进行相同的迭代
从文件或管道读取
- 3 child 已启动并正在等待输入
- 3 个数字和换行符立即可用
- 第一个 child 的底层
read
读取并消耗 stdio 缓冲区中的所有输入
- 第一个 child(获得读取的那个)有它的
scanf
调用解码输入的(第一部分)并进行处理
但现在另外 2 个 child 正在从位于文件末尾的 file/pipe 读取。他们scanf returns 0 但是你控制不了,他们让初始未定值在num
.
您可以通过在循环前添加 sleep(10)
来控制它不是竞争条件问题,启动程序并在第一个 child 开始读取之前手动输入 3 个数字。由于低级读取将以换行符终止(特殊的 tty 情况),即使在第一次读取之前有 3 行可用,您仍然会得到与第一种情况相同的输出。
我有这个小程序:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main() {
int orig = 1;
for (int i = 0; (i != 3) && orig; ++i) {
orig = orig && fork();
}
if (orig) {
for (int i = 0; i != 3; ++i) {
wait(NULL);
}
} else {
int num;
scanf("%8d", &num);
printf("%d\n", num*num);
}
}
它应该简单地对从 stdin
中读取的三个数字进行平方。如果我自己输入数字,它会起作用:
akiiino$ ./out.out
12345678
12345678
12345678
260846532
260846532
260846532
但是如果我将 cat 用于相同的目的,它不会按预期工作:
akiiino$ cat in.txt
12345678
12345678
12345678
akiiino$ cat in.txt | ./out.out
260846532
0
0
这种奇怪行为背后的原因是什么,是否可以修复?我一直认为 cat
编辑文件与将它们输入 stdin
.
@Some programmer dude 已经说过,问题出在 fork
命令上。
如果您尝试 ./out.out < in.txt
,它应该可以正常工作。
不同之处在于,当您手动键入 3 个数字时,您是从终端读取并且低级读取在换行处终止。让我们看看幕后发生了什么。
手动输入:
- 3 child 已启动并正在等待输入
- 您键入一个数字并换行
- 基础
read
调用被换行符终止,因为您从终端读取 - 第一个 child(获得读取的)
scanf
调用解码输入并进行处理
好的,我们对另外两个 childs
进行相同的迭代
从文件或管道读取
- 3 child 已启动并正在等待输入
- 3 个数字和换行符立即可用
- 第一个 child 的底层
read
读取并消耗 stdio 缓冲区中的所有输入 - 第一个 child(获得读取的那个)有它的
scanf
调用解码输入的(第一部分)并进行处理
但现在另外 2 个 child 正在从位于文件末尾的 file/pipe 读取。他们scanf returns 0 但是你控制不了,他们让初始未定值在
num
.
您可以通过在循环前添加 sleep(10)
来控制它不是竞争条件问题,启动程序并在第一个 child 开始读取之前手动输入 3 个数字。由于低级读取将以换行符终止(特殊的 tty 情况),即使在第一次读取之前有 3 行可用,您仍然会得到与第一种情况相同的输出。