Why system () returns 0, even if the program it runs dies

I am trying to check a piece of code ( $code), which should ensure that only one instance of the program starts at a time:

#!/usr/bin/perl
# test_lock
use strict;
use warnings;

( my $code = <<'CODE') =~ s/^\s+//gm;
    #!/usr/bin/perl
    use strict;
    use warnings;
    use Fcntl qw(:flock);

    # Make sure only one instance of the program is running at a time.
    open our $Lock, '<', $0 or die "Can't lock myself $0: $!";
    flock $Lock, LOCK_EX | LOCK_NB
      or die "Another instance of $0 is already running. Exiting ...\n";

    sleep(2);
CODE

my $progfile = '/tmp/x';
open my $fh, '>', $progfile or die $!;
print $fh $code;
close $fh;

$|++;
my $ex1 = system("perl $progfile &");
print "First system(): $ex1\n";
my $ex2 = system("perl $progfile");
print "Second system(): $ex2\n";

I was expecting the second call to system()return a non-zero value ( $ex2), since it cannot get the lock and dies. However, I get:

$ perl test_lock
First system(): 0
Another instance of /tmp/x is already running. Exiting ...
Second system(): 0

What is wrong with my assumption? (Is there a better way to check $code?)

+4
source share
2 answers

I think this is likely because you have a race condition. How do you know that the error actually comes from your second process?

Because if, for example, you run:

perl /tmp/x & perl /tmp/x ; echo $?

, "" ( , ). ( , )

, - :

, , , (/bin/sh -c Unix, ). , execvp, .

, sh perl , , , , .

, :

sh -c "perl /tmp/x"& perl /tmp/x; echo $?

, . , "" , , !

linux - strace -fTt yourscript, . $$ process-pid .

+5

. , .

, system("perl $progfile &"), , 0, perl .

, perl , . , .

#!/usr/bin/perl
# test_lock
use strict;
use warnings;

( my $code = <<'CODE') =~ s/^\s+//gm;
    #!/usr/bin/perl
    use strict;
    use warnings;
    use Fcntl qw(:flock);

    # Make sure only one instance of the program is running at a time.
    open our $Lock, '<', $0 or die "Can't lock myself $0: $!";
    flock $Lock, LOCK_EX | LOCK_NB
      or die "$ARGV[0]: Another instance of $0 is already running. Exiting ...\n";

    sleep(2);
CODE

my $progfile = 'b.pl';
open my $fh, '>', $progfile or die $!;
print $fh $code;
close $fh;

$|++;
my $ex1 = system("perl $progfile 1 &");
print "First system(): $ex1\n";
my $ex2 = system("perl $progfile 2");
print "Second system(): $ex2\n";

:

$ perl a.pl
First system(): 0
1: Another instance of b.pl is already running. Exiting ...
Second system(): 0

$ perl a.pl
First system(): 0
2: Another instance of b.pl is already running. Exiting ...
Second system(): 2816
+4

Source: https://habr.com/ru/post/1616517/


All Articles