简体   繁体   中英

Locking a file for both read and write

I am writing an application where two processes needs to update the same file file.txt . There is a chance that this will happen at the same time, so I should implement some locking framework.

Each process needs to first read all of file.txt , process it, and then write out a modified verison of file.txt . So the lock should be obtained before the first file read, and released after the write. I checked out flock in Fcntl but it seems it can only lock on a filehandle, so the lock is lost after the first read (since I have to close the file, before I can reopen it for writing later)..

Also, if one process has locked the file, and the other process tries to lock it, it should not abort, but implement some sort of non-busy waiting until the other file releases the lock on the file.

How can this locking scheme best be implemented? Is there a CPAN module that I can use?

flock will do what you need. Note that it is a cooperative measure, so other processes will need to use the same system otherwise there will be nothing to stop them doing what they like with the file.

With regard to losing the lock on the file, you have two obvious choices

  • Acquire the lock on a separate file that exists only to control access to the primary file. This is probably the tidiest method

  • Open the file with both read and write access using a mode of +< . That will allow you to read through the file and then rewrite after using seek and truncate

Each process should try to acquire an exclusive lock with flock $fh, LOCK_EX , and will wait until its turn to access the file.

You should use

use Fcntl qw/ :flock :seek /;

to import the relevant constants for these operations.

Here's an example of the first method, which uses a separate lock file to control access to a data file that has just one record containing a count. Note that the lock file must be created outside the process, as any attempt to check whether it exists and create it if not will cause a race condition in the sharing processes

use strict;
use warnings;
use 5.010;
use autodie;

use Fcntl qw/ :flock /;

my ($data_file, $lock_file) = qw/ data.txt lockfile.lock /;

open my $lock_fh, '<', $lock_file;
flock $lock_fh, LOCK_EX;

open my $data_fh, '<', $data_file;
chomp(my $record = <$data_fh>);

open $data_fh, '>', $data_file;
print $data_fh ++$record, "\n";

close $data_fh;

close $lock_fh;

and here's an example of the second method, which does the same thing but without using a separate lock file and instead opening the data file read/write. In the same way that the lock file above must be created independently of the sharing processes, the data file here must be created as a separate action. The locking system won't prevent two processes from creating a new file simultaneously so it cannot be left to them to do it

use strict;
use warnings;
use 5.010;
use autodie;

use Fcntl qw/ :flock :seek /;

my $data_file = 'data.txt';

open my $data_fh, '+<', $data_file;
flock $data_fh, LOCK_EX;

chomp(my $record = <$data_fh>);

seek $data_fh, 0, SEEK_SET;
truncate $data_fh, 0;
print $data_fh ++$record, "\n";

close $data_fh;

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