Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

How can I read DATA in parent and child?

by Skeeve (Parson)
on Feb 18, 2019 at 13:33 UTC ( [id://1230099]=perlquestion: print w/replies, xml ) Need Help??

Skeeve has asked for the wisdom of the Perl Monks concerning the following question:

I'm trying to read DATA in a parent and in a child process, but seem to be unable to achieve this.

Simply using <DATA> didn't work.

So I tried fdopen, but still just the parent seems to be able to read my DATA.

What am I doing wrong?

use IO::Handle; use strict; use warnings; my $x= IO::Handle->new(); $x->fdopen(fileno(DATA), "r"); my $y= IO::Handle->new(); $y->fdopen(fileno(DATA), "r"); my $pid= fork(); die unless defined $pid; if ($pid == 0) { print "Start c\n"; while (<$x>) { print "c: $_"; sleep 1; } print "stop c\n"; } else { print "Start p\n"; while (<$y>) { print "p: $_"; sleep 1; } print "stop p\n"; } __DATA__ a b c d e

Output is:

Start p p: a Start c stop c p: b p: c p: d p: e stop p

Update In an earlier version I mixed up parent and child. Fixed.


s$$([},&%#}/&/]+}%&{})*;#$&&s&&$^X.($'^"%]=\&(|?*{%
+.+=%;.#_}\&"^"-+%*).}%:##%}={~=~:.")&e&&s""`$''`"e

Replies are listed 'Best First'.
Re: How can I read DATA in parent and child?
by choroba (Cardinal) on Feb 18, 2019 at 14:13 UTC
    Interesting. Even duplicating the DATA handle in the child doesn't help.
    open my $d2, '<&', *DATA or die $!;

    But opening the script itself again works, using tell to find the position of the DATA section:

    #!/usr/bin/perl use warnings; use strict; open my $d2, '<', $0 or die $!; seek $d2, tell *DATA, 0; if (fork) { while (<DATA>) { print "parent: $_"; } } else { while (<$d2>) { print "child: $_"; } exit } __DATA__ a b c
    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
Re: How can I read DATA in parent and child?
by hdb (Monsignor) on Feb 18, 2019 at 14:10 UTC

    I assume that this is a simplified example and that you are trying to understand the issue rather looking for a workaround, but in just in case... you could read the DATA before forking...

    use strict; use warnings; my @data = <DATA>; my $pid= fork(); die unless defined $pid; if ($pid == 0) { print "Start c\n"; for (@data) { print "c: $_"; sleep 1; } print "stop c\n"; } else { print "Start p\n"; for (@data) { print "p: $_"; sleep 1; } print "stop p\n"; } __DATA__ a b c d e

    I admit that I do not know either what the fork/DATA problem is. If you put in a sleep statement before the loop you can control whether the parent or the child reads the DATA segment but this is not helpful either.

Re: How can I read DATA in parent and child?
by tybalt89 (Monsignor) on Feb 18, 2019 at 17:13 UTC

    If you want, you can read alternately in the parent and the child.

    (Using sysread because it is unbuffered.)

    #!/usr/bin/perl # https://perlmonks.org/?node_id=1230099 use strict; use warnings; $| = 1; my $me = fork() ? 'parent' : ' child'; while( sysread DATA, $_, 1 ) { print $me eq 'parent' ? uc : lc; select undef, undef, undef, 0.1; } 1 while wait > 0; __DATA__ one two three four five six seven eigth nine ten

    Outputs (on my machine) :

    OnE TwO ThReE FoUr fIvE SiX SeVeN EiGtH NiNe tEn

    Posted because I think it's funny :)

    EDIT: fixed incomplete output paste.

Re: How can I read DATA in parent and child?
by Skeeve (Parson) on Feb 18, 2019 at 14:17 UTC

    So I just noticed: It seems to have to do with buffering.

    When I appen a lot of lines containing some "x" I received response from parent and child:

    $ perl x Start p p: a Start c c: x c: xxxxxxxxxx p: b c: xxxxxxxxxx p: c c: xxxxxxxxxx p: d c: xxxxxxxxxx p: e c: xxxxxxxxxx p: xxxxxxxxxx

    s$$([},&%#}/&/]+}%&{})*;#$&&s&&$^X.($'^"%]=\&(|?*{%
    +.+=%;.#_}\&"^"-+%*).}%:##%}={~=~:.")&e&&s""`$''`"e

      This works:

      use IO::Handle; use strict; use warnings; my $x= IO::Handle->new(); $x->fdopen(fileno(DATA), "r"); my $y= IO::Handle->new(); $y->fdopen(fileno(DATA), "r"); my $pos= tell *DATA; my $pid= fork(); die unless defined $pid; if ($pid == 0) { seek $x, $pos, 0; print "Start c\n"; while (<$x>) { print "c: $_"; sleep 1; } print "stop c\n"; } else { seek $y, $pos, 0; print "Start p\n"; while (<$y>) { print "p: $_"; sleep 1; } print "stop p\n"; } __DATA__ a b c d e

      Simply reposition the filepointer…


      s$$([},&%#}/&/]+}%&{})*;#$&&s&&$^X.($'^"%]=\&(|?*{%
      +.+=%;.#_}\&"^"-+%*).}%:##%}={~=~:.")&e&&s""`$''`"e

        The docs on fork perlfork say that parent and child share the same seek pointer:

        Any filehandles open at the time of the fork() will be dup()-ed. Thus, the files can be closed independently in the parent and child, but beware that the dup()-ed handles will still share the same seek pointer. Changing the seek position in the parent will change it in the child and vice-versa. One can avoid this by opening files that need distinct seek pointers separately in the child.

        So I find it surprising that this version works.

Re: How can I read DATA in parent and child?
by karlgoethebier (Abbot) on Feb 19, 2019 at 16:43 UTC

    I wonder what you really want to do. As far as I understood you want to read from a file from two different processes, right? The use of <DATA> is just a simplification.

    Please correct me if i‘m wrong.

    You may consider to use MCE::Hobo. If you don‘t use threads it forks.

    Please see Re: Parallel trigger of different subs as well as the whole thread ibidem for inspiration.

    Minor update: Fixed typo.

    Best Regards, Karl

    «The Crux of the Biscuit is the Apostrophe»

    perl -MCrypt::CBC -E 'say Crypt::CBC->new(-key=>'kgb',-cipher=>"Blowfish")->decrypt_hex($ENV{KARL});'Help

      Hi karlgoethebier,

      Update: Ah, the OP wants to read DATA independently. See tybalt89's solution.

      Update: Currently, the following demos work on Unix platforms with IO::FDPass: automatically loaded by MCE::Shared if present in Perl. The next update to MCE::Shared on CPAN will support reading from the DATA handle without involving IO::FDPass and work on Windows including Cygwin.

      MCE::Shared works similarly with threads and MCE::Hobo.

      threads demonstration

      use strict; use warnings; use threads; use MCE::Shared; mce_open my $shared_fh, '<', \*DATA; async { print "Start Thread\n"; while (<$shared_fh>) { print "T: $_"; sleep 1; } print "Stop Thread\n"; }; print "Start Parent\n"; while (<$shared_fh>) { print "P: $_"; sleep 1; } print "Stop Parent\n"; $_->join for threads->list; __DATA__ a b c d e f g h i j

      MCE::Hobo demonstration

      use strict; use warnings; use MCE::Hobo; use MCE::Shared; mce_open my $shared_fh, '<', \*DATA; mce_async { print "Start Child\n"; while (<$shared_fh>) { print "C: $_"; sleep 1; } print "Stop Child\n"; }; print "Start Parent\n"; while (<$shared_fh>) { print "P: $_"; sleep 1; } print "Stop Parent\n"; MCE::Hobo->waitall; __DATA__ a b c d e f g h i j

      Regards, Mario

        Thank you Mario. Regards, Karl

        «The Crux of the Biscuit is the Apostrophe»

        perl -MCrypt::CBC -E 'say Crypt::CBC->new(-key=>'kgb',-cipher=>"Blowfish")->decrypt_hex($ENV{KARL});'Help

Re: How can I read DATA in parent and child?
by Anonymous Monk on Feb 18, 2019 at 14:58 UTC

    Verrrry interrrresting!

    About 10 minutes' rummaging in the docs failed to find any explanation.

    Some playing with the code says that what we have is a race. If you sleep in the parent before reading, the child gets the data.

    Further playing says that if you seek before reading, both parent and child get the data. I was using the DATA handle directly, so my seek was
    seek( DATA, tell( DATA ), 0 );.
    Note that this actually works without the parentheses, but I included them for clarity.

Re: How can I read DATA in parent and child?
by marioroy (Prior) on Feb 20, 2019 at 02:50 UTC

    Hi Skeeve,

    Update: Ah, the OP wants to read DATA independently. See tybalt89's solution.

    Update: Currently, the following demo works on Unix platforms with IO::FDPass: automatically loaded by MCE::Shared if present in Perl. The next update to MCE::Shared on CPAN will support reading from the DATA handle without involving IO::FDPass and work on Windows including Cygwin.

    MCE::Shared is not exclusive to only MCE parallel modules: e.g. MCE, MCE::Flow, MCE::Hobo, and etcetera. MCE::Shared also works with threads, even fork shown below, and other parallel modules found on metacpan.

    Code

    use strict; use warnings; use MCE::Shared; mce_open my $shared_fh, '<', \*DATA; my $pid= fork(); die unless defined $pid; if ($pid == 0) { print "Start Child\n"; while (<$shared_fh>) { print "C: $_"; sleep 1; } print "Stop Child\n"; } else { print "Start Parent\n"; while (<$shared_fh>) { print "P: $_"; sleep 1; } print "Stop Parent\n"; } __DATA__ a b c d e f g h i j

    Output

    Start Parent Start Child P: a C: b C: c P: d C: e P: f C: g P: h C: i P: j Stop Child Stop Parent

    Regards, Mario

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1230099]
Front-paged by haukex
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others pondering the Monastery: (4)
As of 2024-03-28 17:49 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found