2010-08-10 110 views
5

我正在寻找一个简单的已经实现的解决方案,在MATLAB中原子创建一个文件锁定。原子创建一个文件锁定在MATLAB(文件互斥)

喜欢的东西:

file_lock('create', 'mylockfile'); %this will block until it creates the lock file. 
file_lock('remove', 'mylockfile'); %this will remove the lock file: 

这个问题已经被问了好几次,一些提出的解决思路(比如使用Java FileLock), 但我没有找到一个简单的已经实施的解决方案。

你知道这样一个实施的解决方案吗?

注:

+3

我讨厌被扫兴,但这是极难得到一个正确的一般的方式,尤其是网络文件。文件锁定与系统高度相关。没有简单的,已经实施的解决方案没有被破坏。 (不难写出“似乎主要工作”的东西;很难写出一些不会在生产中失败的东西。)让我们回过头来看看:你想要同步访问什么?它是文件内容还是文件代表其他资源?您定位的平台是什么?如何“正确”你需要排除? – 2010-08-10 21:31:43

回答

0

写入到一个新的文件,然后将其重命名。重命名是一个原子操作,所有新内容将立即变为可见。

+0

这个想法也在http://groups.google.com/group/comp.soft-sys.matlab/browse_thread/thread/eb4ebeb8700ea440/13bd6710e8429a70?lnk=raot 中提出,但事实证明,unix的重命名不是原子的(首先删除dest文件,然后重新命名源文件),并且matlab使用unix在unix中重命名,因此该解决方案也不起作用。 – 2010-08-10 17:10:06

+0

只要读取该线程。共识似乎是MatLab的'movefile'命令不仅仅是一个'rename'调用,所以'movefile'不是原子的。 SUS非常清楚,'rename'在unix上是原子化的(当然,如果你使用的是一个类Unix的克隆,它不符合规范就是另一回事)。 http://opengroup.org/onlinepubs/007908775/xsh/rename.html – 2010-08-10 19:20:53

0

最后我做了一个基于两个连续测试(移动文件,并验证移动文件的内容)的实现。

写得不是很好,但它现在适用于我。

+++++ file_lock.m ++++++++++++++++++++++++

function file_lock(op, filename) 
%this will block until it creates the lock file: 
%file_lock('create', 'mylockfile') 
% 
%this will remove the lock file: 
%file_lock('remove', 'mylockfile') 


% todo: verify that there are no bugs 

filename = [filename '.mat']; 

if isequal(op, 'create') 
    id = [tempname() '.mat'] 
    while true 
    save(id, 'id'); 
    success = fileattrib(id, '-w'); 
    if success == 0; error('fileattrib'); end 

    while true 
     if exist(filename, 'file');  %first test 
     fprintf('file lock exists(1). waiting...\n'); 
     pause(1); 
     continue; 
     end 
     status = movefile(id, filename); %second test 
     if status == 1; break; end 
     fprintf('file lock exists(2). waiting...\n'); 
     pause(1); 
    end 

    temp = load(filename, 'id');   % third test. 
    if isequal(id, temp.id); break; end 

    fprintf('file lock exists(3). waiting...\n'); 
    pause(1) 
    end 

elseif isequal(op, 'remove') 
    %delete(filename); 
    execute_rs(@() delete(filename)); 

else 
    error('invalid op'); 
end 



function execute_rs(f) 
while true 
    try 
    lastwarn(''); 
    f(); 
    if ~isequal(lastwarn, ''); error(lastwarn); end %such as: Warning: File not found or permission denied 
    break; 
    catch exception 
    fprintf('Error: %s\n.Retrying...\n', exception.message); 
    pause(.5); 
    end 
end 

+++++++ +++++++++++++++++++++++

+0

我认为如果一个工作人员在'movefile'之前被中断,你就会遇到问题。 – 2010-08-10 19:13:42

5

我已经解决了一个非常简单的解决方案错误/将来自多个工作线程的消息记录到单个文件中。每次我想写入该文件时,首先将输出写入该线程自己的临时文件。接下来,我使用flock将该临时文件追加到“主”日志文件中。这里跳过一些细节,这个想法是:

fid=fopen(threadtemp, 'w'); 
fprintf(fid, 'Error message goes here'); 
fclose(fid); 

runme = sprintf('flock -x %s -c ''cat %s >> %s''', LOGFILE, threadtemp, LOGFILE); 
system(runme); 

详见羊群手册页,但调用以上,取得该日志文件的独占锁,锁下运行所提供的命令,然后将其释放。

这显然只适用于一个有flock的系统(Linux/OS X,并且只有某些类型的文件系统),而且你正在做一些可以从命令行完成的工作,但我敢打赌,这是一个非常常见的用例。

+0

只是想知道,为什么你要通过创建临时文件的步骤?为什么不只是像系统('flock -x日志文件-c''回显errormessage >>日志文件''')?谢谢 – Grittathh 2013-04-09 19:07:43

+0

没有特别的理由 - 你的方法应该工作得很好。我认为我的一些原始函数使用文件名进行登录,所以这让我可以不加修改地使用它们,但我想大多数情况下它是残缺的。唯一真正的技巧是使用system()来调用flock。 – 2013-04-09 19:45:32

1

根据其Java版本你正在使用,也许这将工作(从翻译:http://www.javabeat.net/2007/10/locking-files-using-java/

classdef FileLock < handle 
    properties (Access = private) 
     fileLock = [] 
     file 
    end 

    methods 
     function this = FileLock(filename) 
      this.file = java.io.RandomAccessFile(filename,'rw'); 
      fileChannel = this.file.getChannel(); 
      this.fileLock = fileChannel.tryLock(); 
     end 

     function val = hasLock(this) 
      if ~isempty(this.fileLock) && this.fileLock.isValid() 
       val = true; 
      else 
       val = false; 
      end 
     end 

     function delete(this) 
      this.release(); 
     end 

     function release(this) 
      if this.hasLock 
       this.fileLock.release(); 
      end 
      this.file.close 
     end 
    end 
end 

用法是:

lock = FileLock('my_lock_file'); 
if lock.hasLock 
    %// do something here 
else 
    %// I guess not 
end 
%// Manually release the lock, or just delete (or let matlab clean it up) 

我喜欢IO obj的包装模式因此即使在例外情况下也可以释放

编辑:必须将文件参考文件保留在周围并手动关闭,否则您将无法编辑该文件。这意味着这个代码只对纯锁文件有用,我想。

0

如果你只需要在OS X和Linux版本(非Windows)上运行,你可以使用以下命令:

pathLock='/tmp/test.lock' 

% Try to create and lock this file. 
% In my case I use -r 0 to avoid retrying 
% You could use -r -1 to retry forever, or for a particular amount of time, 
% etc, see `man lockfile` for details. 
if ~system(sprintf('lockfile -r 0 %s',pathLock)) 
    % We succeeded, so perform some task which needs to be serialized. 
    % runSerializedTask() 
    % Now remove the lockfile 
    system(sprintf('rm -f %s',pathLock)); 
end 
+0

请注意,关于这种方法在网络文件系统中是否安全有许多讨论。 lockfile手册页说它是“NFS-resistant”,但我不确定这意味着什么:)或是否涵盖了所有这些问题(它们变得相当复杂!) – nonagon 2015-10-27 16:09:52