2010-10-06 35 views
5

Tôi đang viết một chương trình hỗ trợ nhiều quy trình con và tôi muốn tất cả các quy trình con này có thể viết dòng STDERRSTDOUT mà không cần đầu ra bị cắt xén. Tôi không làm bất cứ điều gì ưa thích, chỉ phát ra các dòng kết thúc bằng một dòng mới (điều đó, ít nhất trong sự hiểu biết của tôi sẽ là một hoạt động nguyên tử cho Linux). Từ perlfaq nó nói:fork() và STDOUT/STDERR vào giao diện điều khiển từ các tiến trình con

Cả quy trình chính và nền được xử lý (quy trình "con") đều có cùng tệp STDIN, STDOUT và STDERR. Nếu cả hai cố gắng truy cập chúng cùng một lúc, những điều kỳ lạ có thể xảy ra. Bạn có thể muốn đóng hoặc mở lại những thứ này cho đứa trẻ. Bạn có thể giải quyết vấn đề này bằng cách mở một đường ống (xem mở) nhưng trên một số hệ thống, điều này có nghĩa là quá trình con không thể sống lâu hơn với cha mẹ.

Điều đó nói rằng tôi nên "đóng hoặc mở lại" các tệp này cho trẻ. Kết thúc rất đơn giản, nhưng "reopen" có nghĩa là gì? Tôi đã thử một cái gì đó như thế này từ trong quá trình con tôi và nó không hoạt động (đầu ra vẫn bị cắt xén):

open(SAVED_STDERR, '>&', \*STDERR) or die "Could not create copy of STDERR: $!"; 
close(STDERR); 

# re-open STDERR 
open(STDERR, '>&SAVED_STDERR') or die "Could not re-open STDERR: $!"; 

Vì vậy, tôi đang làm gì với điều này? Ví dụ về đường ống sẽ ám chỉ như thế nào? Có cách nào tốt hơn để phối hợp đầu ra từ nhiều quy trình với nhau để bàn điều khiển?

Trả lời

9

Ghi vào một tập tin đính kèm là NOT nguyên tử cho STDOUT và STDIN. Có những trường hợp đặc biệt cho những thứ như fifos nhưng đó không phải là tình hình hiện tại của bạn.

Khi mở lại STDOUT, điều đó có nghĩa là "tạo một cá thể STDOUT mới" Phiên bản mới này không giống với phiên bản gốc của bố mẹ. Đó là cách bạn có thể có nhiều thiết bị đầu cuối mở trên hệ thống của bạn và không có tất cả các STDOUT đi đến cùng một vị trí.

Giải pháp ống sẽ kết nối trẻ với cha mẹ qua đường ống (như | trong vỏ) và bạn cần phải để cha mẹ đọc ra khỏi ống và ghép chính đầu ra. Phụ huynh sẽ chịu trách nhiệm đọc từ đường ống và đảm bảo rằng nó không xen kẽ đầu ra từ đường ống và đầu ra được đặt trước STDOUT của cha mẹ cùng một lúc. Có một ví dụ và ghi here của đường ống.

Một snippit:

use IO::Handle; 

pipe(PARENTREAD, PARENTWRITE); 
pipe(CHILDREAD, CHILDWRITE); 

PARENTWRITE->autoflush(1); 
CHILDWRITE->autoflush(1); 

if ($child = fork) { # Parent code 
    chomp($result = <PARENTREAD>); 
    print "Got a value of $result from child\n"; 
    waitpid($child,0); 
} else { 
    print PARENTWRITE "FROM CHILD\n"; 
    exit; 
} 

Xem cách đứa trẻ không viết thư cho stdout nhưng thay vì sử dụng các đường ống để gửi một thông điệp tới các phụ huynh, ai làm việc viết với stdout của nó. Hãy chắc chắn để có một cái nhìn như tôi bỏ qua những thứ như đóng xử lý tập tin không cần thiết.

+0

Tôi đã kết thúc với IO :: Pipe và AnyEvent cho các đường ống và lựa chọn IO, nhưng điều đó dường như hoạt động. Cảm ơn – mpeters

1

Mặc dù điều này không giúp ích cho bạn, nhưng tôi đã mất nhiều thời gian để tìm cách khởi chạy quy trình con có thể được viết bởi quy trình gốc và có trình tự stderr và stdout của quá trình con được gửi trực tiếp đến màn hình (điều này giải quyết các vấn đề khó chịu chặn bạn có thể có khi cố gắng đọc từ hai FD khác nhau mà không cần sử dụng một cái gì đó ưa thích như chọn).

Khi tôi figured it out, giải pháp là tầm thường

my $pid = open3(*CHLD_IN, ">&STDERR", ">&STDOUT", 'some child program'); 
# write to child 
print CHLD_IN "some message"; 
close(CHLD_IN); 
waitpid($pid, 0); 

Tất cả mọi thứ từ "một số chương trình con" sẽ được phát ra để stdout/stderr, và bạn chỉ có thể bơm dữ liệu bằng văn bản cho CHLD_IN và tin tưởng rằng nó sẽ chặn nếu bộ đệm của trẻ lấp đầy. Đối với người gọi của chương trình mẹ, tất cả chỉ trông giống như stderr/stdout.

Các vấn đề liên quan