2016-10-13 138 views
2

我正在运行一个脚本,它从一个特定的位置复制一个文件夹,如果它不存在(或不一致)。当我连续运行脚本2+次时出现问题。当第一个脚本试图复制这些文件时,第二个脚本来了,并尝试导致一团糟的同样的事情。我怎么能避免这种情况?像系统互斥体一样。检测文件正被复制到一个文件夹中

我tryed一个简单的测试与-w,我手动复制的文件夹,而该文件夹复制我运行该脚本:

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"; 
} 

当然,这是行不通的,因为我还是写存取权限该文件夹。 任何想法如何检查文件夹是否被复制到Perl或使用batch commands

回答

7

听起来像lock file的工作。有无数的CPAN模块实现锁定文件,但其中大多数不能在Windows上工作。这里有几个似乎根据CPAN测试人员支持Windows:

源代码有一个快速查看后,我只能推荐的模块是File :: Flock :: Tiny。其他人看起来很活泼。

+1

因此,为了知道我仍然在该文件夹中进行复制,我会保留一个特定的文件,直到我完成复制整个文件夹并且该文件将被检查为止。 –

+0

@JohnDoe是的,你必须使用一个单独的文件作为锁定文件。 – nwellnhof

3

作为第一个脚本试图复制文件,第二来得快, 尝试导致混乱同样的事情

一个最简单的方法是创建其中将包含1,如果一个文件脚本的另一个实例正在运行。然后你可以添加一个条件的基础上。

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

另一种方法是在脚本中设置环境变量,并检查它在BEGIN块。

+3

这是容易出现竞争情况的Windows的信号量的对象。 – nwellnhof

+2

谢谢你的回答,这真的很聪明,但我可能会从文件夹中移动问题,正如@nwellnhof所说,在文件夹中包含该标志。 –

4

如果您需要系统范围的互斥锁,那么一个“技巧”就是(ab)使用一个目录。命令mkdir通常是原子的,可以工作或不工作(如果该目录已经存在)。

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"; 
} 

你需要确保的唯一的事情是,你允许/tmp创建一个目录(或地方):

如下更改脚本。

注意,我故意做首先测试的$mutex_dir存在,因为之间的if (not -d $mutex_dir)mkdir别人可以创建目录和mkdir无论如何都会失败。所以只需拨打mkdir即可。如果它工作,那么你可以做你的东西。完成后请不要忘记删除$mutex_dir

这也是这种方法的缺点:如果您的复制代码崩溃并且脚本过早死亡,那么目录不会被删除。推测在nwellnhof's answer中建议的锁文件机制在这种情况下表现更好,并自动解锁文件。

+0

这有可能会失败吗?任何特殊情况? –

+0

整个事情取决于'mkdir'的原子性。在Unix下,操作是原子的。在Windows下,我不太确定,谷歌在这里停止了帮助。我发现了两个陈述。 _If_'mkdir'在Windows下是原子的,那么我不知道这种方法会失败的情况(除了缺少权限)。 – PerlDuck

1

您可以使用Windows的互斥或包 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... 
} 
+0

这也是一个有趣的方法,但我想坚持默认出现的模块。 –

相关问题