After reviewing the presentation that Dominus gave to the Philadelphia PM group, I decided to revisit a module I had written, and implement some better file locking procedures. Here is the module so far:
package Logger::Simple; use strict; use Carp; use FileHandle; use Fcntl qw(:flock); use vars qw /$VERSION $SEM/; $VERSION='1.06'; $SEM = ".LS.lock"; sub new{ my($class,%args)=@_; my $self = bless{LOG => $args{LOG} || croak"No logfile!\n", CARP => $args{CARP} || undef, FILEHANDLE => new FileHandle || croak"Unable to ge +t filehandle\n", SEMAPHORE => new FileHandle || croak"Unable to cr +eate semaphore filehandle\n", ERROR => "", HISTORY => [], },$class; if(! $self->open()){ die"Unable to open $self->{LOG}\n"; } return $self; } sub open{ my $self=shift; if(! open($$self{FILEHANDLE},">>$$self{LOG}")){ $self->set("Unable to open logfile\n"); return 0; } $$self{FILEHANDLE}->autoflush(1); return 1; } sub write{ my($self,$msg)=@_; my $FH=*{$$self{FILEHANDLE}}; my $format="$0 : [".scalar (localtime)."] $msg"; $self->lock(); if(! print $FH "$format\n"){ $self->set("Unable to write to $$self{LOG}: $!\n"); } $self->unlock(); } sub message{ my $self=shift; if(wantarray){ my @messages=@{$$self{HISTORY}}; return @messages; }else{ my $message=$$self{ERROR}; return $message; } } sub clear{ my $self=shift; $$self{ERROR}=undef; } sub set{ my ($self,$error)=@_; $self->clear; $$self{ERROR}=$error; push @{$$self{HISTORY}},$error; carp "$error\n" if $$self{CARP}; $self->write($error); } sub print_object{ require Data::Dumper; my $self=shift; print Data::Dumper->Dumper($self); } sub lock{ my $self=shift; my $FH=*{$$self{SEMAPHORE}}; if(-e $SEM){ flock($FH,LOCK_NB) or carp"Can't obtain file lock: $!\n"; open($FH,">$SEM")||die"Can't create lock file: $!\n"; flock($FH,LOCK_EX) or die"Can't obtain file lock: $!\n"; }else{ open $FH,">$SEM"||die"Can't create lock file: $!\n"; flock($FH,LOCK_EX) or die"Can't obtain file lock: $!\n"; } } sub unlock{ my $self=shift; my $FH=*{$$self{SEMAPHORE}}; if(-e $SEM){ flock(S,LOCK_UN); close S; unlink $SEM; } } 1;
By using cron to run a couple of simple scripts that use the same log file to write to, I notice that the write statement from the second script are intermingled with those from the first inside the log file, which is fine and is doing what I expected. However, if I start the two scripts from a shell script (it runs the first script in the background and starts the second one), I get the following errors:
Ambiguous call resolved as CORE::open(), qualify as such or use & at / +opt/perl5/ lib/site_perl/5.6.0/Logger/Simple.pm line 88. Ambiguous call resolved as CORE::open(), qualify as such or use & at / +opt/perl5/ lib/site_perl/5.6.0/Logger/Simple.pm line 88. Ambiguous call resolved as CORE::open(), qualify as such or use & at / +opt/perl5/ lib/site_perl/5.6.0/Logger/Simple.pm line 91. Ambiguous call resolved as CORE::open(), qualify as such or use & at / +opt/perl5/ lib/site_perl/5.6.0/Logger/Simple.pm line 91. Use of uninitialized value in ref-to-glob cast at /opt/perl5/lib/site_ +perl/5.6.0 /Logger/Simple.pm line 85. Use of uninitialized value in ref-to-glob cast at /opt/perl5/lib/site_ +perl/5.6.0 /Logger/Simple.pm line 85. flock() on closed filehandle main:: at /opt/perl5/lib/site_perl/5.6.0/ +Logger/Sim ple.pm line 87. more lines follow ...
Here are the scripts in question:
#!/opt/perl5/bin/perl # locker.pl use strict; use Logger::Simple; my $L=Logger::Simple->new(LOG=>"file.txt",CARP=>'1'); for(1..10){ $L->write("Writing");} #!/opt/perl5/bin/perl -w # writer.pl use strict; use Logger::Simple; my $L=Logger::Simple->new(LOG=>"file.txt",CARP=>'1') for(1..5){ $L->write("Getting through?"); } #!/bin/sh # runner.sh ./locker.pl & ./writer.pl
To note something however, the behavior of the scripts is the same as far as writing into the log file. How can I get rid of these warning messages (other than run without warnings)?

TStanley
--------
It is God's job to forgive Osama Bin Laden. It is our job to arrange the meeting -- General Norman Schwartzkopf

In reply to File locking with semaphores by TStanley

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.