【问题标题】:atomically creating a file lock in MATLAB (file mutex)在 MATLAB 中原子地创建文件锁(文件互斥锁)
【发布时间】:2010-08-10 16:48:03
【问题描述】:

我正在寻找一个简单的已经实现的解决方案,用于在 MATLAB 中以原子方式创建文件锁。

类似:

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

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

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

注意事项:

【问题讨论】:

  • 我讨厌做一个湿毯子,但这很难以一般方式纠正,尤其是对于网络文件。文件锁定高度依赖于系统。没有简单的、已经实施的解决方案不会被破坏。 (写一些“似乎主要工作”的东西并不难;很难写一些不会在某处生产中失败的东西。)让我们退后一步:你想同步访问什么?是文件内容,还是文件代表其他资源?你的目标是什么平台?您需要排除在多大程度上“正确”?

标签: file matlab concurrency locking mutex


【解决方案1】:

我已经确定了一个非常简单的解决方案,将来自多个工作线程的错误/日志消息合并到一个文件中。每次我想写入该文件时,我首先将输出写入线程自己的临时文件。接下来,我使用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 man page的详细信息,但上面的调用是在日志文件上获取一个排他锁,在锁下运行提供的命令,然后释放它。

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

【讨论】:

  • 只是想知道,您为什么要经过创建临时文件的步骤?为什么不只是像 system('flock -x logfile -c '' echo errormessage >> logfile '' ') 之类的东西?谢谢
  • 没有特别的原因——你的方法应该可以正常工作。我认为我的一些原始函数使用文件名来登录,所以这让我可以不加更改地使用它们,但我猜它主要是退化的。唯一真正的技巧是使用 system() 来调用flock。
【解决方案2】:

根据您使用的 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 包装模式,这样即使在异常情况下也会发生释放

编辑:文件 ref 必须保留并手动关闭,否则您将无法对其进行编辑。这意味着我认为这段代码只对纯锁文件真正有用。

【讨论】:

    【解决方案3】:

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

    【讨论】:

    • 这个想法在groups.google.com/group/comp.soft-sys.matlab/browse_thread/…中也有提出,但事实证明unix的重命名不是原子的(先删除dest文件,然后重命名源文件),而matlab在unix中使用的是unix的rename,所以这个解决方案也不起作用。
    • 只需阅读该主题即可。共识似乎是 MatLab 的 movefile 命令不仅仅是一个 rename 调用,所以 movefile 不是原子的。 SUS 很清楚 rename 在 unix 上是原子的(当然,如果您使用的是不符合规范的类 Unix 克隆,那就是另一回事了)。 opengroup.org/onlinepubs/007908775/xsh/rename.html
    【解决方案4】:

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

    写得不是很好,但它现在对我有用。

    +++++ 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
    

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

    【讨论】:

    • 我认为如果工作人员在movefile 之前被打断,您会遇到问题。
    【解决方案5】:

    如果你只需要在 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
    

    【讨论】:

    • 请注意,有很多关于这种方法在网络文件系统上是否安全的讨论。 lockfile 手册页说它是“抗 NFS”的,但我不确定这是什么意思 :) 或者它是否涵盖了所有关于此的问题(它们变得非常复杂!)
    猜你喜欢
    • 2015-04-14
    • 1970-01-01
    • 1970-01-01
    • 2013-06-25
    • 2018-05-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多