简体   繁体   中英

Detecting that files are being copied in a folder

I am running a script which copies one folder from a specific location if it does not exist( or is not consistent). The problems appears when I run concurently the script 2+ times. As the first script is trying to copy the files, the second comes and tryes the same thing resulting in a mess. How could I avoid this situation? Something like system wide mutex.

I tryed a simple test with -w , I manually copied the folder and while the folder was copying I run the script:

use strict;
use warnings;

my $filename = 'd:\\folder_to_copy';
if (-w $filename) {
  print "i can write to the file\n";
} else {
  print "yikes, i can't write to the file!\n";
}

Of course this won't work, cuz I still have write acces to that folder. Any ideea of how could I check if the folder is being copied in Perl or using batch commands ?

Sounds like a job for a lock file . There are myriads of CPAN modules that implement lock files, but most of them don't work on Windows. Here are a few that seem to support Windows according to CPAN Testers:

After having a quick view at the source code, the only module I can recommend is File::Flock::Tiny . The others seem racy.

If you need a systemwide mutex, then one "trick" is to (ab)use a directory. The command mkdir is usually atomic and either works or doesn't (if the directory already exists).

Change your script as follows:

my $mutex_dir = '/tmp/my-mutex-dir';
if ( mkdir $mutex_dir ) {

    # run your copy-code here

    # when finished:
    rmdir $mutex_dir;
} else {
    print "another instance is already running.\n";
}

The only thing you need to make sure is that you're allowed to create a directory in /tmp (or wherever).

Note that I intentionally do NOT firstly test for the existence of $mutex_dir because between the if (not -d $mutex_dir) and the mkdir someone else could create the directory and the mkdir would fail anyway. So simply call mkdir . If it worked then you can do your stuff. Don't forget to remove the $mutex_dir after you're done.

That's also the downside of this approach: If your copy-code crashes and the script prematurely dies then the directory isn't deleted. Presumably the lock file mechanism suggested in nwellnhof's answer behaves better in that case and automatically unlocks the file.

As the first script is trying to copy the files, the second comes and tries the same thing resulting in a mess

A simplest approach would be to create a file which will contain 1 if another instance of script is running. Then you can add a conditional based on that.

{local $/; open my $fh, "<", 'flag' or die $!; $data = <$fh>};
die "another instance of script is running" if $data == 1;

Another approach would be to set an environment variable within the script and check it in BEGIN block.

You can use Windows-Mutex or Windows-Semaphore Objects of the package http://search.cpan.org/~cjm/Win32-IPC-1.11/

use Win32::Mutex;
use Digest::MD5 qw (md5_hex);
my $mutex = Win32::Mutex->new(0, md5_hex $filename);
if ($mutex) {
     do_your_job();
     $mutex->release
} else {
     #fail...
}

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