다음을 수행하는 프로그램 A가 있습니다.
- 입력에서 2바이트 읽기
- 입력 읽기를 인쇄합니다.
exec
프로그램 B를 입력합니다.
프로그램 B는 다음을 수행합니다.
- 입력에서 2바이트 읽기
- 인쇄 입력
구체적으로 다음은 옵션 A와 B입니다.
ㅏ:
#include <unistd.h>
#include <stdio.h>
int main(){
char a[3];
fgets(a, 3, stdin);
printf("%s\n", a);
char* args[] = {NULL};
execv("./read2", args);
}
두번째:
#include <stdio.h>
int main(){
char a[] = "hy";
fgets(a, 3, stdin);
printf("%s\n", a);
}
이렇게 실행하면 echo 'abcd' | ./A
다음과 같은 결과가 나올 것으로 예상됩니다.
ab
cd
하지만 난 ab hy를 갖고 있어
B
표준 입력에서 읽지 못하는 이유는 무엇입니까 ?
답변1
TLDR: 후속 프로세스가 부모가 중지된 위치를 정확히 읽어야 하는 경우 부모는 버퍼링되지 않은 IO를 사용해야 합니다.
버퍼링되지 않은 IO의 경우 프로그램이 올바르게 작동합니다.
#include <stdio.h>
#include <string.h>
#include <unistd.h>
char buf[3];
int main(int argc, char *argv[])
{
read(STDIN_FILENO, buf, 2);
printf("%s '%s'\n", *argv, buf);
if (strcmp(*argv, "./childtu") == 0) return 0;
execl("./readtwo", "./childtu", (char *) 0);
}
실행하여
$ make readtwo
cc readtwo.c -o readtwo
$ echo abcdefg | ./readtwo
./readtwo 'ab'
./childtu 'cd'
$
부모의 버퍼링된 IO(통과)가 fgets
문제입니다. 부모가 미리 읽을 수 있는 것보다 더 많은 입력이 있는 경우 자식은 표준 입력에서만 읽을 수 있기 때문입니다.
#include <stdio.h>
#include <string.h>
#include <unistd.h>
char buf[3];
int main(int argc, char *argv[])
{
fgets(buf, 3, stdin);
printf("%s '%s'\n", *argv, buf);
if (strcmp(*argv, "./childtu") == 0) return 0;
execl("./readtwo", "./childtu", (char *) 0);
}
궁금하다면 정확한 버퍼 크기에 대한 이진 검색을 수행하거나 커널에 설정된 내용을 확인할 수 있습니다.
$ perl -e 'print(("a")x99999)' | ./readtwo
./readtwo 'aa'
./childtu 'aa'
$
(또는 이와 유사한) 방법을 사용하면 상위 프로세스가 표준 입력(fd 0)에서 strace
얼마나 나오는지 관찰할 수 있습니다 .read
$ echo asdf | strace -o blah ./readtwo
./readtwo 'as'
./childtu ''
$ fgrep 'read(0' blah
read(0, "asdf\n", 4096) = 5
read(0, "", 4096) = 0
$
여기서 상위 프로세스는 4096바이트를 원했지만(5바이트만 얻었음) exec
'd 프로세스는 아무것도 남지 않았기 때문에 0을 얻었습니다. 따라서 이것이 문제가 된다면 상위 프로세스에서 버퍼링된 읽기를 사용하지 마십시오.