?? setfilesemaphore.m
字號:
function semaphore = setfilesemaphore(fileList)
%SETFILESEMAPHORE Set semaphore for file access.
% SEMAPHORE = SETFILESEMAPHORE(FILENAME) sets a semaphore to get
% exclusive access on file FILE. The semaphore is realized by generating
% a simple Matlab data file after checking that no other semaphores are
% existing. The function exits if the semaphore is set. Exclusive file
% access is of course only guaranteed if all other Matlab processes use
% semaphores to access the same file.
%
% The output variable SEMAPHORE is needed to correctly remove the file
% semaphore after file access. It is an error to call function
% SETFILESEMAPHORE without output arguments.
%
% SEMAPHORE = SETFILESEMAPHORE(FILELIST) sets semaphores for all files
% given in cell array FILELIST. Note that function SETFILESEMAPHORE waits
% for exclusive file access on ALL files in the list before exiting.
%
% Note: A semaphore older than 20 seconds is considered as invalid and
% will immediately be deleted.
%
% Example:
% sem = setfilesemaphore('test.mat');
% % access file test.mat here
% dir test.mat.semaphore.*
% removefilesemaphore(sem);
%
% Markus Buehren
% Last modified 21.04.2008
%
% See also REMOVEFILESEMAPHORE.
persistent filesToIgnore
% set times (all in seconds)
semaphoreOldTime = 30;
fixedWaitTime = 0.01;
checkWaitTime = 0.1;
waitInfoPeriod = 5;
maxRandomTime = 0.3;
if nargout ~= 1
error('Function %s must be called with one output argument!', mfilename);
end
if ischar(fileList)
% single file given
fileList = {fileList};
end
nOfFiles = length(fileList);
semaphore = cell(nOfFiles, 1);
for fileNr = 1:nOfFiles
fileName = fileList{fileNr};
% check if given file is itself a semaphore file
if ~isempty(regexp(fileName, '\.semaphore\.\w+\.\d{32}\.mat$', 'once'))
semaphore{fileNr, 1} = '';
continue
end
% generate semaphore file name and pattern
[ignore, randomStr] = generaterandomnumber; %#ok
semaphoreFileName = [fileName, '.semaphore.', gethostname, '.', randomStr, '.mat'];
semaphorePattern = [fileName, '.semaphore.*.mat'];
semaphorePatternPath = fileparts(semaphorePattern);
startWaitTime = now;
displayWaitInfo = true;
while 1
dirStruct = dir(semaphorePattern);
if ~isempty(dirStruct)
% other semaphore file(s) existing
% check if any semaphore is very old
allSemaphoresOld = true;
for k=1:length(dirStruct)
if now - datenum2(dirStruct(k).date) > semaphoreOldTime / (3600*24)
oldSemaphoreFileName = concatpath(semaphorePatternPath, dirStruct(k).name);
% avoid to issue more than one warning for each file
ignoreThisFile = ismember(oldSemaphoreFileName, filesToIgnore);
if ~ignoreThisFile
filesToIgnore{end+1} = oldSemaphoreFileName; %#ok
% limit the number of saved files
if length(filesToIgnore) > 2000
filesToIgnore = filesToIgnore(end-1000:end);
end
end
% turn off file permission warnings
warnID = 'MATLAB:DELETE:Permission';
warnState = warning('query', warnID);
warning('off', warnID);
if existfile(oldSemaphoreFileName)
% try to remove semaphore
lastwarn('');
try
% deletion may cause an error or a file permission warning
delete(oldSemaphoreFileName);
catch
if ~ignoreThisFile
disp(textwrap2(sprintf('Warning: Error occured in removing old semaphore of file %s.', fileName)));
end
end
% check last warning
if ~ignoreThisFile
[lastMsg, lastID] = lastwarn;
if strcmp(lastID, warnID)
disp(textwrap2(sprintf('Warning: Unable to remove old semaphore of file %s.', fileName)));
end
end
end
warning(warnState);
else
allSemaphoresOld = false;
end
end
if allSemaphoresOld
continue
end
% display info
if displayWaitInfo && (now - startWaitTime)*86400 >= waitInfoPeriod
disp(sprintf('Waiting for semaphore of file %s to disappear.', fileName));
displayWaitInfo = false;
end
% wait before checking again
pause(checkWaitTime);
else
% set own semaphore file
try
save(semaphoreFileName, 'randomStr');
%fclose(fopen(semaphoreFileName, 'w'));
catch
disp(sprintf('An error occured while accessing semaphore file %s:', semaphoreFileName));
displayerrorstruct;
% in very very very unlikely cases two processes might have
% generated the same semaphore file name
[randomNr, randomStr] = generaterandomnumber; %#ok
pause(0.2+maxRandomTime * randomNr);
semaphoreFileName = [fileName, '.semaphore.', gethostname, '.', randomStr, '.mat'];
%save(semaphoreFileName, 'randomStr');
[fid, message] = fopen(semaphoreFileName, 'w');
if fid == -1
disp(message);
else
fclose(fid);
end
end
% wait fixed time
pause(fixedWaitTime);
% in very unlikely cases, two semaphore files might have been created
% at the same time
dirStruct = dir(semaphorePattern);
if length(dirStruct) > 1
% remove own semaphore file
delete(semaphoreFileName);
% wait RANDOM time before checking again
pause(maxRandomTime * generaterandomnumber);
else
% exclusive file access is guaranteed
% save semaphore file name and leave while loop
semaphore{fileNr, 1} = semaphoreFileName;
break
end
end % if ~isempty(dirStruct)
end % while 1
end % for fileNr = 1:nOfFiles
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [randomNr, randomStr] = generaterandomnumber
%GENERATERANDOMNUMBER
% in very unlikely cases, it might happen that the random states of rand
% and randn are equal in two Matlab processes calling function
% SETSEMAPHORE. For this reason, the system and cpu time are used to
% create different random numbers even in this unlikely case.
%
% This all were not necessary if it were possible to get some sort of a
% Matlab process ID.
nOfDigits = 8; % length of random string will be 4*nOfDigits
randNr = rand;
randnNr = mod(randn+0.5, 1);
cputimeNr = mod(cputime, 100)/100;
nowNr = mod(rem(now,1)*3600*24, 100)/100;
% random number is used for random pause after conflict
randomNr = 0.25 * (randNr + randnNr + cputimeNr + nowNr);
% random string is used for the semaphore file name
if nargout > 1
ee = 10^nOfDigits;
randomStr = [...
num2str(ee * randNr, '%.0f'), ...
num2str(ee * randnNr, '%.0f'), ...
num2str(ee * cputimeNr, '%.0f'), ...
num2str(ee * nowNr, '%.0f'), ...
];
end
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -