실행 프로세스가 표준 입력에서 읽히지 않습니다.

실행 프로세스가 표준 입력에서 읽히지 않습니다.

다음을 수행하는 프로그램 A가 있습니다.

  1. 입력에서 2바이트 읽기
  2. 입력 읽기를 인쇄합니다.
  3. exec프로그램 B를 입력합니다.

프로그램 B는 다음을 수행합니다.

  1. 입력에서 2바이트 읽기
  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을 얻었습니다. 따라서 이것이 문제가 된다면 상위 프로세스에서 버퍼링된 읽기를 사용하지 마십시오.

관련 정보