Perl无法写入子进程中的文件句柄

时间:2013-11-06 10:45:40

标签: perl

我需要将一些数据写入child中的文件句柄。文件句柄是在分叉之前在父文件中创建的。这是因为我可以从父文件句柄中读取数据,因为fork保留文件句柄并锁定它们(如果有的话),在父和子之间共享。这是在Linux和Windows平台上共享父和子的数据。我能够在Linux中使用IPC :: Shareable进行数据共享,这在windows中不起作用,因为windows中没有semaphore.pm [windos不支持semaphore.pm],所以对于windows我试过Win32 :: MMF哪个崩溃了我的perl编译器。

因此,使用文件句柄方法,IO写入不会发生在子级中。请查看以下代码


use strict;
use warnings;

print "creating file\n"; 
open FH, ">testfile.txt" or die "cant open file: $!\n";
close FH;

my $pid = fork();

if ( $pid == 0 )
{
print "entering in to child and opening file for write\n";
open FH, ">>testfile.txt" or die "cant open file: $!\n";
print FH "dummy data\n";
print FH "dummy data\n";     
print "child sleeping for 5 sec before exiting\n";
sleep 50;
exit;

}
else
{
print "entering the parent process\n";   
open FH, "<testfile.txt" or die "cant open file: $!\n";
 print <FH>;
 print <FH>;


}

3 个答案:

答案 0 :(得分:2)

父进程应至少等待一小段时间才能让孩子有时间写作。

use strict;
use warnings;

print "creating file\n";
open my $FH, ">", "testfile.txt" or die "cant open file: $!\n";
close $FH;

my $pid = fork();

if ( $pid == 0 ) {
  print "entering in to child and opening file for write\n";
  open my $FH, ">>", "testfile.txt" or die "cant open file: $!\n";
  print $FH "dummy data\n";
  print $FH "dummy data\n";

  # print "child sleeping for 5 sec before exiting\n";
  # sleep 50;
  exit;
}
else {
  sleep 1;
  print "entering the parent process\n";
  open my $FH, "<", "testfile.txt" or die "cant open file: $!\n";
  print while <$FH>;
}

输出

creating file
entering in to child and opening file for write
entering the parent process
dummy data
dummy data

答案 1 :(得分:2)

感谢您帮我解决这个问题。我试图解决这个问题昨天发现了一个关于fork的有趣的事情,同时使用它与文件句柄在子和父之间共享数据,即我们可以使用以下代码解决问题,并且技巧是在fork之前和内部打开文件句柄child只是写入文件句柄而不重新打开它。以下是修改后的代码。

use strict;
use warnings;
use Fcntl qw(:flock SEEK_END);

print "creating file handle\n"; 
open my $FH, ">testfile.txt" or die "cant open file: $!\n";
#close FH;

my $pid = fork();

if ( $pid == 0 )
{
 print "entering in to child and opening file for write\n";
 #open FH, ">>testfile.txt" or die "cant open file: $!\n";

   # Put a exclusive lock in the filehandle for dening access to any other process   during this child process run
   flock($FH, LOCK_EX) or die "Cannot lock testfile.txt - $!\n";

   # and, in case someone appended while we were waiting...
   seek($FH, 0, SEEK_END) or die "Cannot seek - $!\n";



   # write data to temp file with exclusive lock on it   
    print $FH "dummy data\n";
    print $FH "dummy data\n";

   # remove the lock once writing is done
    flock($FH, LOCK_UN) or die "Cannot unlock temp.txt - $!\n";

 print "child sleeping for 5 sec before exiting\n";
 sleep 2;
 exit;

}
else
{
 print "entering the parent process\n"; 
 #flock(FH, LOCK_UN) or die "Cannot unlock temp.txt - $!\n";

 sleep 3;    
 open $FH, "<testfile.txt" or die "cant open file: $!\n";

 while (<$FH>){
 print "$_\n";
 }
}

答案 2 :(得分:0)

正如mpapec所说,你很容易受到竞争条件的影响,在这种情况下,父母在孩子读完之前从文件中读取。如果您打算让子进程缓慢生成输出并让父进程相对快速地处理它,那么父进程将经常读取文件末尾。您将需要了解如何使用seek重置文件结束标记并等待更多输入:

# parent process, after fork
sleep 1;         # give child time to create, write to file
open my $fh, '<', 'testfile.txt';
while (1) {

    my $line = <$fh>;
    if (defined($line)) {
        print $line;       # or  process($line)

        # another way (other than waitpid, see below) to see if the child is
        # finished is to use some convention between parent and child,
        # like having the child print "DONE!\n" as the last output it produces
        last if $line eq "DONE!\n";

    } else {

        # parent is starved for input. Is the child finished or is it just slow?
        use POSIX ':sys_wait_h';
        my $wpid = waitpid $pid, &WNOHANG;
        if ($wpid == $pid) {
            # child process has exited
            last;
        } else {
            # child is just slow. Clear the eof on $fh
            sleep 1;
            seek $fh, 0, 1;
        }
    }
}
close $fh;

您真正应该做的另一件事是在子进程中刷新输出。除非您非常快速地产生大量输出,否则输出将花费时间在缓冲区中并且父级无法访问:

if ( $pid == 0 ) {
  print "entering in to child and opening file for write\n";
  open my $fh, ">>", "testfile.txt" or die "cant open file: $!\n";

  $fh->autoflush(1);          # force OS to send output to disk right away

  print $fh "dummy data\n";
  print $fh "dummy data\n";

  print "child sleeping for 5 sec before exiting\n";
  sleep 5.0;
  # print $fh "DONE!\n";
  close $fh;
  exit;
}

进程间通信非常棘手,但要非常强大。继续练习。