2010-08-10 108 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