使用Perl以非阻塞方式从文件描述符读取

时间:2014-08-14 15:46:59

标签: perl fork pipe

假设我有这个:

pipe(READ,WRITE);
$pid = fork();
if ($pid == 0) {
    close(READ);
    # do something that may be blocking
    print WRITE "done";
    close(WRITE);
    exit(0);
} else {
    close(WRITE);
    $resp = <READ>;
    close(READ);
    # do other stuff
}

在这种情况下,孩子可能会无限期地挂起。有没有办法我可以在READ读取一段时间(即超时),如果我什么都没有得到,我会假设孩子挂了? p>

2 个答案:

答案 0 :(得分:1)

通常,在C或Perl中,您使用 select()来测试是否有可用的输入。如果您愿意,可以指定超时 0 ,但在下面的示例中使用 1秒。:

use IO::Select;
pipe(READ,WRITE);
$s = IO::Select->new();
$s->add(\*READ);
$pid = fork();
if ($pid == 0) {
    close(READ);
    # do something that may be blocking
    for $i (0..2) {
        print "child - $i\n";
        sleep 1;
    }
    print WRITE "donechild";
    close(WRITE);
    print "child - end\n";
    exit(0);
} else {
    print "parent - $pid\n";
    close(WRITE);
    for $i (0..10) {
        print "parent - $i\n";
            # 1 second wait (timeout) here.  Can be 0.
        print "parent - ", (@r=$s->can_read(1))?"yes":"no", "\n";
        last if @r;
    }

    $resp = <READ>;
    print "parent - read: $resp\n";
    close(READ);
    # do other stuff
} 

答案 1 :(得分:0)

  

我有没有办法从READ读取一段时间(即超时),如果我没有得到任何东西,我会假设孩子正在挂起而继续做父母?

当你分叉时,你正在使用两个完全独立的进程。您正在运行程序的两个单独副本。您的代码无法在程序中的父级和子级之间来回切换。你的节目是父母或孩子。

您可以在父级中使用alarm向您的父进程发送 SIGALRM 。如果我没记错的话,您可以设置$SIG{ALRM}子程序,启动闹钟,进行读取,然后将alarm设置为零以将其关闭。整件事需要包裹在eval

我很久以前就做过这个。出于某种原因,我记得标准系统读取不起作用。您必须使用sysread。有关更多帮助,请参阅Perl Signal Processing