2010-08-10 10 views
5

Ich bin auf der Suche nach einer einfachen bereits implementierten Lösung zum atomaren Erstellen einer Dateisperre in MATLAB.atomar Erstellen einer Dateisperre in MATLAB (Datei Mutex)

Etwas wie:

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

Diese Frage bereits mehrmals mit einigen vorgeschlagenen Lösungsideen (wie der Verwendung von Java FileLock), aber ich habe nicht gefunden, eine einfache bereits implementierte Lösung gefragt wurde.

Kennen Sie eine solche implementierte Lösung?

Hinweise:

+3

Ich hasse eine nasse Decke zu sein, aber das ist extrem schwierig, richtig in eine bekommen allgemeine Art und Weise, insbesondere für Netzwerkdateien. Die Dateisperrung ist stark systemabhängig. Es wird keine einfache, bereits implementierte Lösung geben, die nicht kaputt ist. (Es ist nicht schwierig, etwas zu schreiben, das "meistens zu funktionieren scheint"; schwer, etwas zu schreiben, das in der Produktion nicht fehlschlägt.) Lass uns einen Moment zurückgehen: Wonach versuchst du den Zugang zu synchronisieren? Sind es die Dateiinhalte oder stellen die Dateien eine andere Ressource dar? Auf welche Plattformen zielen Sie? Wie "korrekt" brauchen Sie den Ausschluss? –

Antwort

0

Schreiben in eine neue Datei, dann umbenennen. Das Umbenennen ist eine atomare Operation und der gesamte neue Inhalt wird sofort sichtbar.

+0

Diese Idee wurde auch in http://groups.google.com/group/comp.soft-sys.matlab/browse_thread/thread/eb4ebeb8700ea440/13bd6710e8429a70?lnk=raot vorgeschlagen, aber es stellt sich heraus, dass die Umbenennung von Unix nicht atomar ist (zuerst löscht er die Zieldatei, dann die Quelldatei, die umbenannt wird), und Matlab verwendet die Unix-Umbenennung in Unix, , so dass diese Lösung auch nicht funktioniert. –

+0

Lesen Sie einfach diesen Thread. Der Konsens scheint zu sein, dass MatLabs "movefile" -Befehl mehr als nur einen einzigen 'rename'-Aufruf ausführt, so dass' movefile' nicht atomar ist. Der SUS ist ziemlich klar, dass "Umbenennen" atomar auf Unix ist (natürlich, wenn Sie einen Unix-ähnlichen Klon verwenden, der nicht der Spezifikation entspricht, die eine andere Geschichte ist). http://opengroup.org/onlinepubs/007908775/xsh/rename.html –

0

Am Ende habe ich eine Implementierung basierend auf zwei aufeinanderfolgenden Tests (movefile, und überprüfen Sie den Inhalt der verschobenen Datei).

nicht sehr gut geschrieben, aber es funktioniert für jetzt für mich.

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

Ich denke, Sie haben ein Problem, wenn ein Arbeiter direkt vor 'movefile' unterbrochen wird. –

5

Ich habe mich auf eine ziemlich einfache Lösung für die Kombination festgelegt Fehler/Protokollierung von Nachrichten aus mehreren Worker-Threads in einer einzigen Datei. Jedes Mal, wenn ich in diese Datei schreiben möchte, schreibe ich die Ausgabe zuerst in die temporäre Datei des Threads. Als Nächstes hänge ich diese temporäre Datei mithilfe von flock an die Protokolldatei "master" an. Skipping hier einige Details, die Idee ist:

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); 

die Herd Manpage für Details, aber vor dem Anruf auf der Logdatei eine Schreibsperre erwirbt, unter dem Schloss, um den vorgesehenen Befehl ausgeführt wird, und dann die Freigabe .

Dies funktioniert natürlich nur, wenn Sie auf einem System sind, das Flock hat (Linux/OS X, und nur bestimmte Arten von Dateisystemen) und Sie tun etwas, das über die Befehlszeile getan werden kann, aber Ich würde wetten, dass es ein ziemlich häufiger Anwendungsfall ist.

+0

nur wundernd, warum gehen Sie durch den Schritt der Erstellung der temporären Datei? warum nicht einfach etwas wie system ('flock -x logfile -c' 'echo fehlermeldung >> logfile' '')? Danke – Grittathh

+0

Kein besonderer Grund - Ihr Ansatz sollte gut funktionieren. Ich denke, dass einige meiner ursprünglichen Funktionen Dateinamen verwendet haben, um sich anzumelden, so dass ich sie ohne Änderungen verwenden kann, aber es ist größtenteils rudimentär, denke ich. Der einzige wirkliche Trick ist die Verwendung von system(), um flock aufzurufen. –

1

Je nachdem, welche Java-Version Sie verwenden, vielleicht funktioniert das (übersetzt aus: 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 

Verwendung wäre:

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) 

ich das obj Verpackungsmuster wie für IO so dass Freigabe auch in Ausnahmen

EDIT: Die Datei Ref muss herum bleiben und manuell geschlossen werden, oder Sie können dies nicht bearbeiten. Das bedeutet, dass dieser Code nur für reine Lock-Dateien wirklich nützlich ist, denke ich.

0

Wenn Sie nur auf OS X und Linux ausgeführt werden müssen (nicht Windows), können Sie die folgenden Befehle verwenden:

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

Beachten Sie, dass es viele Diskussionen darüber gibt, ob solche Ansätze in vernetzten Dateisystemen sicher sind. Die Lockfile-Manpage sagt, dass es "NFS-resistent" ist, aber ich bin mir nicht sicher, was das bedeutet :) oder ob es alle Bedenken diesbezüglich deckt (sie werden ziemlich kompliziert!) – nonagon