2016-12-05 18 views
11

Tôi đang triển khai một chương trình giống như trình bao trong C++. Nó có một vòng lặp mà đọc từ cin, dĩa, và chờ đợi cho đứa trẻ.Trong C++, gọi fork khi cin là một bash heredoc gây ra các đoạn đầu vào lặp đi lặp lại

Tính năng này hoạt động tốt nếu đầu vào tương tác hoặc được nhập từ chương trình khác. Tuy nhiên, khi đầu vào là bash heredoc, chương trình sẽ ghi lại các phần của đầu vào (đôi khi vô thời hạn).

Tôi hiểu rằng quy trình con kế thừa các mô tả tệp của cha mẹ, bao gồm bù đắp tệp được chia sẻ. Tuy nhiên, đứa trẻ trong ví dụ này không đọc bất cứ điều gì từ cin, vì vậy tôi nghĩ rằng nó không nên chạm vào bù đắp. Tôi khá lo lắng về việc tại sao điều này lại xảy ra.


test.cpp:

#include <iostream> 
#include <unistd.h> 
#include <sys/wait.h> 

int main(int argc, char **argv) 
{ 
    std::string line; 
    while (std::getline(std::cin, line)) { 
     pid_t pid = fork(); 
     if (pid == 0) { // child 
      break; // exit immediately 
     } 
     else if (pid > 0) { // parent 
      waitpid(pid, nullptr, 0); 
     } 
     else { // error 
      perror("fork"); 
     } 

     std::cout << getpid() << ": " << line << "\n"; 
    } 
    return 0; 
} 

tôi biên dịch nó như sau:

g++ test.cpp -std=c++11 

Sau đó, tôi chạy nó với:

./a.out <<EOF 
hello world 
goodbye world 
EOF 

Output:

012.351.
7754: hello world 
7754: goodbye world 
7754: goodbye world 

Nếu tôi thêm một dòng thứ ba foo bar để lệnh đầu vào, chương trình bị mắc kẹt trong một vòng lặp vô hạn:

13080: hello world 
13080: goodbye world 
13080: foo bar 
13080: o world 
13080: goodbye world 
13080: foo bar 
13080: o world 
[...] 

phiên bản:

  • Linux kernel: 4.4.0 -51-generic
  • Ubuntu: 16.04.1 LTS (xenial)
  • bash: GNU bash , Phiên bản 4.3.46 (1) -release (x86_64-pc-linux-gnu)
  • gcc: g ++ (Ubuntu 5.4.0-6ubuntu1 ~ 16.04.4) 5.4.0 20160609
+1

Điều gì sẽ xảy ra nếu bạn thực hiện 'std :: ios :: sync_with_stdio (false);' ngay từ đầu và sau đó xóa hoàn toàn sau khi bạn viết thành stdout? (ví dụ: thay đổi ''\ n'' thành' std :: endl') – Hurkyl

+3

Bằng cách truy tìm tiến trình con, tôi có thể thấy chính xác những gì đang xảy ra. Quá trình con lseeks ngược về bộ mô tả tập tin 0 trước khi thoát, điều này ảnh hưởng đến tiến trình cha. Thật không may, tôi không biết tại sao thư viện C lại làm điều đó, vì vậy tôi sẽ không đăng các chi tiết như một câu trả lời. Điều này cũng xảy ra với một 'thoát (0)', nhưng không phải '_exit (0);'. –

+1

câu trả lời ở đây có thể hữu ích http://stackoverflow.com/questions/33899548/file-pointers-after-returning-from-a-forked-child-process – Erix

Trả lời

1

tôi đã có thể để tái tạo vấn đề này, không chỉ sử dụng heredoc mà còn sử dụng chuyển hướng tập tin chuẩn.

Đây là tập lệnh thử nghiệm mà tôi đã sử dụng. Trong cả hai trường hợp đầu tiên và thứ hai, tôi nhận được một bản sao của dòng thứ hai của đầu vào.

./a.out < Input.txt 
echo 

cat Input.txt | ./a.out 
echo 

./a.out <<EOF 
hello world 
goodbye world 
EOF 

Đóng stdin trước khi thoát khỏi trẻ có vẻ như loại bỏ cả hai vấn đề.

#include <iostream> 
#include <sstream> 
#include <unistd.h> 
#include <sys/wait.h> 
#include <limits> 

int main(int argc, char **argv) 
{ 
    std::string line; 
    while (std::getline(std::cin, line)) { 
     pid_t pid = fork(); 
     if (pid == 0) { // child 
      close(STDIN_FILENO); 
      break; // exit after first closing stdin 
     } 
     else if (pid > 0) { // parent 
      waitpid(pid, nullptr, 0); 
     } 
     else { // error 
      perror("fork"); 
     } 

     std::cout << getpid() << ": " << line << "\n"; 
    } 
    return 0; 
} 
Các vấn đề liên quan