1function semaphore = setfilesemaphore(fileList) 2%SETFILESEMAPHORE Set semaphore for file access. 3% SEMAPHORE = SETFILESEMAPHORE(FILENAME) sets a semaphore to get 4% exclusive access on file FILE. The semaphore is realized by generating 5% a simple Matlab data file after checking that no other semaphores are 6% existing. The function exits if the semaphore is set. Exclusive file 7% access is of course only guaranteed if all other Matlab processes use 8% semaphores to access the same file. 9% 10% The output variable SEMAPHORE is needed to correctly remove the file 11% semaphore after file access. It is an error to call function 12% SETFILESEMAPHORE without output arguments. 13% 14% SEMAPHORE = SETFILESEMAPHORE(FILELIST) sets semaphores for all files 15% given in cell array FILELIST. Note that function SETFILESEMAPHORE waits 16% for exclusive file access on ALL files in the list before exiting. 17% 18% Note: A semaphore older than 20 seconds is considered as invalid and 19% will immediately be deleted. 20% 21% Markus Buehren 22% Last modified 13.11.2007 23% 24% See also REMOVEFILESEMAPHORE. 25 26% set times (all in seconds) 27semaphoreOldTime = 20; 28fixedWaitTime = 0.01; 29checkWaitTime = 0.1; 30maxRandomTime = 0.3; 31 32if nargout ~= 1 33 error('Function %s must be called with one output argument!', mfilename); 34end 35 36if ischar(fileList) 37 % single file given 38 fileList = {fileList}; 39end 40 41nOfFiles = length(fileList); 42semaphore = cell(nOfFiles, 1); 43for fileNr = 1:nOfFiles 44 45 fileName = fileList{fileNr}; 46 47 % check if given file is itself a semaphore file 48 if ~isempty(regexp(fileName, '\.semaphore\.\w+\.\d{32}\.mat$', 'once')) 49 semaphore{fileNr, 1} = ''; 50 continue 51 end 52 53 % generate semaphore file name and pattern 54 [ignore, randomStr] = generaterandomnumber; %#ok 55 semaphoreFileName = [fileName, '.semaphore.', randomStr, '.mat']; 56 semaphorePattern = [fileName, '.semaphore.', '*', '.mat']; 57 semaphorePatternPath = fileparts(semaphorePattern); 58 59 while 1 60 dirStruct = dir(semaphorePattern); 61 62 if ~isempty(dirStruct) 63 % other semaphore file(s) existing 64 % check if any semaphore is very old 65 allSemaphoresOld = true; 66 for k=1:length(dirStruct) 67 if now - datenum2(dirStruct(k).date) > semaphoreOldTime / (3600*24) 68 % remove semaphore 69 disp(sprintf('Warning: Removing old semaphore file %s.', dirStruct(k).name)); 70 oldSemaphoreFileName = fullfile(semaphorePatternPath, dirStruct(k).name); 71 if exist(oldSemaphoreFileName, 'file') 72 delete(oldSemaphoreFileName); 73 end 74 else 75 allSemaphoresOld = false; 76 end 77 end 78 79 if allSemaphoresOld 80 continue 81 end 82 83 % wait before checking again 84 pause(checkWaitTime); 85 86 else 87 % set own semaphore file 88 try 89 save(semaphoreFileName, 'randomStr'); 90 catch 91 disp(sprintf('An error occured while accessing semaphore file %s:', semaphoreFileName)); 92 displayerrorstruct; 93 94 % in very very very unlikely cases two processes might have 95 % generated the same semaphore file name 96 [randomNr, randomStr] = generaterandomnumber; %#ok 97 pause(0.2+maxRandomTime * randomNr); 98 semaphoreFileName = [fileName, '.semaphore.', randomStr, '.mat']; 99 save(semaphoreFileName, 'randomStr'); 100 end 101 102 % wait fixed time 103 pause(fixedWaitTime); 104 105 % in very unlikely cases, two semaphore files might have been created 106 % at the same time 107 dirStruct = dir(semaphorePattern); 108 if length(dirStruct) > 1 109 % remove own semaphore file 110 delete(semaphoreFileName); 111 112 % wait RANDOM time before checking again 113 pause(maxRandomTime * generaterandomnumber); 114 115 else 116 % exclusive file access is guaranteed 117 % save semaphore file name and leave while loop 118 semaphore{fileNr, 1} = semaphoreFileName; 119 break 120 end 121 end % if ~isempty(dirStruct) 122 end % while 1 123end % for fileNr = 1:nOfFiles 124 125%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 126function [randomNr, randomStr] = generaterandomnumber 127%GENERATERANDOMNUMBER 128% in very unlikely cases, it might happen that the random states of rand 129% and randn are equal in two Matlab processes calling function 130% SETSEMAPHORE. For this reason, the system and cpu time are used to create 131% different random numbers even in this unlikely case. 132 133nOfDigits = 8; % length of random string will be 4*nOfDigits 134 135randNr = rand; 136randnNr = mod(randn+0.5, 1); 137cputimeNr = mod(cputime, 100)/100; 138nowNr = mod(rem(now,1)*3600*24, 100)/100; 139 140% random number is used for random pause after conflict 141randomNr = 0.25 * (randNr + randnNr + cputimeNr + nowNr); 142 143% random string is used for the semaphore file name 144if nargout > 1 145 ee = 10^nOfDigits; 146 randomStr = [... 147 num2str(ee * randNr, '%.0f'), ... 148 num2str(ee * randnNr, '%.0f'), ... 149 num2str(ee * cputimeNr, '%.0f'), ... 150 num2str(ee * nowNr, '%.0f'), ... 151 ]; 152end 153 154%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 155function dateNr = datenum2(dateStr) 156%DATENUM2 Return serial date number. 157% DATENUM2(STR) returns the serial date number for the given date string 158% STR. Function DATENUM2 is a wrapper for DATENUM which replaces german 159% month abbreviations like "Okt" by the english versions like "Oct" 160% before forwarding the string to function DATENUM. 161% 162% Function DATENUM2 first tries to build a date vector from the given 163% string for performance reasons. However, only date format 0 164% (dd-mmm-yyyy HH:MM:SS) is supported for this. If the given date string 165% is in a different format, the string is forwarded to function DATENUM. 166 167tokenCell = regexp(dateStr, '(\d+)-(\w+)-(\d+) (\d+):(\d+):(\d+)', 'tokens'); 168tokenCell = tokenCell{1}; 169if length(tokenCell) == 6 170 % supported date format (at least it seems so) 171 172 % get month 173 switch tokenCell{2} 174 case 'Jan' 175 month = 1; 176 case 'Feb' 177 month = 2; 178 case {'Mar', 'M�r', 'Mrz'} 179 month = 3; 180 case 'Apr' 181 month = 4; 182 case {'May', 'Mai'} 183 month = 5; 184 case 'Jun' 185 month = 6; 186 case 'Jul' 187 month = 7; 188 case 'Aug' 189 month = 8; 190 case 'Sep' 191 month = 9; 192 case {'Oct', 'Okt'} 193 month = 10; 194 case 'Nov' 195 month = 11; 196 case {'Dec', 'Dez'} 197 month = 12; 198 otherwise 199 % obviously the data format is not supported 200 disp('Date format not supported (1)'); 201 dateNr = datenum(translatedatestr(dateStr)); 202 return 203 end 204 205 dateVec = [... 206 str2double(tokenCell{3}), ... % year 207 month, ... % month 208 str2double(tokenCell{1}), ... % day 209 str2double(tokenCell{4}), ... % hours 210 str2double(tokenCell{5}), ... % minutes 211 str2double(tokenCell{6}), ... % seconds 212 ]; 213 dateNr = datenum(dateVec); 214 215else 216 % unknown date format 217 dateNr = datenum(translatedatestr(dateStr)); 218end 219 220%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 221function dateStr = translatedatestr(dateStr) 222%TRANSLATEDATESTR Translate german date string to english version. 223% STR = TRANSLATEDATESTR(STR) converts a german date string like 224% 13-M�r-2006 15:55:00 225% to the english version 226% 13-Mar-2006 15:55:00. 227% This is needed on some systems if function DIR returns german date 228% strings. 229% 230% Markus Buehren 231% 232% See also DATENUM2. 233 234dateStr = strrep(dateStr, 'Mrz', 'Mar'); 235dateStr = strrep(dateStr, 'M�r', 'Mar'); 236dateStr = strrep(dateStr, 'Mai', 'May'); 237dateStr = strrep(dateStr, 'Okt', 'Oct'); 238dateStr = strrep(dateStr, 'Dez', 'Dec'); 239 240%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 241function displayerrorstruct(errorStruct) 242%DISPLAYERRORSTRUCT Display structure returned by function lasterror. 243% DISPLAYERRORSTRUCT displays the structure returned by function 244% LASTERROR. Useful when catching errors. 245% 246% Markus Buehren 247% 248% See also LASTERROR. 249 250if nargin == 0 251 errorStruct = lasterror; 252end 253 254disp(errorStruct.message); 255errorStack = errorStruct.stack; 256for k=1:length(errorStack) 257 disp(sprintf('Error in ==> %s at %d.', errorStack(k).name, errorStack(k).line)); 258end