简体   繁体   中英

File locking and unlocking from input

I have a subroutine in which i'm trying to exclusively lock a set of files (one at a time) and hold that lock for a certain amount of given time(through sleep ). I'm trying to add the functionality of letting the user unlock the current locked(sleeping) file whenever they press a certain key, such as the enter key. I'm just not sure what direction to go in to get this to work. Every attempt at using STDIN and checking for \\n has not worked. Thanks.

Below is the subroutine. I change to the directory in which I want the files. Create the files from 1 to how ever many files are specified. For each file an exclusive lock is put on then sleeps for a specified amount of time.

Edit: It's my fault for not mentioning this but, this script is going to be run in a Windows environment. I'd ideally like a solution that will not require additional module installation that are not included in Perl. (This was brought up because the module in breqwas' solution does not support Windows). Thanks.

sub lockFiles{
    #creates files that are locked for a specific amount of seconds.
    chdir("lock files")or die "Unable to enter dir $!\n";
    opendir(DIR,".") or die "Can't open the current directory: $!\n";

    #file iterator
    my $i=1;
    #for each file lock it and sleep the given amount of time
    while($i<=$numberOfFiles){
        open FILE, ">>", "test$i.txt" or die $!;
        flock(FILE, 2) or die "Could not lock test$i.txt\n";
        print "test$i.txt locked, locking for $timeToSleep seconds\n";
        print "Press ctrl+c to kill this\n";

        sleep($timeToSleep);

        $i++;
        close(FILE);
    }
    closedir(DIR);
    #change back to the parent folder
    chdir("..") or die "Can't change to the directory: $!\n";
    print "subRoutine lockFiles success\n";
}

I don't have a windows machine w/perl installed to check if that works there, but documentation on Term::ReadKey implies that it should. Term::ReadKey is a module that provides non-blocking and timed read functionality. It has some limited Windows support.

use Time::HiRes qw(time sleep);
use Term::ReadKey;

sub wait_for_key {
    my $timeout = shift;

    my $started = time();
    while (1) {
        last if $started + $timeout < time();

        my $str = '';
        while (my $char = ReadKey(-1)) {
            $str .= $char;
        };

        last if $str =~ m/\n/s;
        sleep 0.1;
    }
}

I'm sure there are better ways to do that, though. Maybe someone with perl-on-windows experience will show up.

Curse on you, Windows. On any other system the code above would look like this:

sub wait_for_key { ReadLine(shift) }

Try smth like that:

use Sys::SigAction qw(sig_alarm set_sig_handler);

sub wait_for_key {
    my $timeout = shift;

    eval {
        my $sa = set_sig_handler('ALRM', sub { die "enough" }, {} );
        eval {
            sig_alarm($timeout);
            my $keyboard = <>;
            sig_alarm(0);
        };
        sig_alarm(0);
    }
}

This function will exit after any input ("Enter" key), or by timeout, so you just call it instead of sleep(). The basic idea is:

1) wait infinitely for the input
2) but set an alarm for the timeout you need.

Looks evil, but works fine.

That's actually a generic way to call some code with a timeout - just make this function accept a second parameter which is a function reference, and call that reference instead of my $keyboard = <> line. And, well, check the errors and do all the boring stuff I left out in this sample.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM