Erstellen einer anderen Datei ist mehr Ärger als alles andere. Erstellen Sie stattdessen ein Verzeichnis und überprüfen Sie das Ergebnis der Erstellung. Das Unix-Handbuch besagt, dass nur ein Task erfolgreich ein Verzeichnis erstellen kann, der andere erhält einen Fehler, wenn das Verzeichnis bereits existiert, einschließlich des Falls, in dem 2 Tasks gleichzeitig versucht haben. Das Betriebssystem selbst behandelt das Problem, sodass Sie es nicht müssen.
Wenn es nicht für mögliche veraltete Schlösser war, ist das alles, was Sie tun müssten. Es passieren jedoch Dinge, Programme brechen ab und entfernen nicht immer ihre Sperre. Die Implementierung kann also etwas aufwendiger sein.
In einem Skript habe ich oft den folgenden Code verwendet. Es verarbeitet veraltete Sperren automatisch.
man -s 2 mkdir
EXECUTION_CONTROL_FILE: Sie können das gleiche in C. Überprüfen Manpage implementieren ist ein Name PATH und Dir Namen, so etwas wie/usr/tmp/myAppName
second_of_now: Rückkehr die aktuelle Zeit in Sekunden (auch weiter unten)
LOCK_MAX_TIME: ist, wie lange in Sekunden ein Schloss kann es vorhanden ist, bevor 5
Schlaf veraltet angesehen wird: es wird immer davon ausgegangen, dass eine Sperre etwas kurz und süß tun wird. Wenn nicht, sollte Ihr Schlafzyklus länger sein.
LockFile() {
L_DIR=${EXECUTION_CONTROL_FILE}.lock
L_DIR2=${EXECUTION_CONTROL_FILE}.lock2
(
L_STATUS=1
L_FILE_COUNT=2
L_COUNT=10
while [ $L_STATUS != 0 ]; do
mkdir $L_DIR 2>/dev/null
L_STATUS=$?
if [ $L_STATUS = 0 ]; then
# Create the timetime stamp file
second_of_now >$L_DIR/timestamp
else
# The directory exists, check how long it has been there
L_NOW=`second_of_now`
L_THEN=`cat $L_DIR/timestamp 2>/dev/null`
# The file does not exist, how many times did this happen?
if [ "$L_THEN" = "" ]; then
if [ $L_FILE_COUNT != 0 ]; then
L_THEN=$L_NOW
L_FILE_COUNT=`expr $L_FILE_COUNT - 1`
else
L_THEN=0
fi
fi
if [ `expr $L_NOW - $L_THEN` -gt $LOCK_MAX_TIME ]; then
# We will try 10 times to unlock, but the 10th time
# we will force the unlock.
UnlockFile $L_COUNT
L_COUNT=`expr $L_COUNT - 1`
else
L_COUNT=10 # Reset this back in case it has gone down
sleep 5
fi
fi
done
)
L_STATUS=$?
return $L_STATUS
}
####
#### Remove access lock
####
UnlockFile() {
U_DIR=${EXECUTION_CONTROL_FILE}.lock
U_DIR2=${EXECUTION_CONTROL_FILE}.lock2
(
# This 'cd' fixes an issue with UNIX which sometimes report this error:
# rm: cannot determine if this is an ancestor of the current working directory
cd `dirname "${EXECUTION_CONTROL_FILE}"`
mkdir $U_DIR2 2>/dev/null
U_STATUS=$?
if [ $U_STATUS != 0 ]; then
if [ "$1" != "0" ]; then
return
fi
fi
trap "rm -rf $U_DIR2" 0
# The directory exists, check how long it has been there
# in case it has just been added again
U_NOW=`second_of_now`
U_THEN=`cat $U_DIR/timestamp 2>/dev/null`
# The file does not exist then we assume it is obsolete
if [ "$U_THEN" = "" ]; then
U_THEN=0
fi
if [ `expr $U_NOW - $U_THEN` -gt $LOCK_MAX_TIME -o "$1" = "mine" ]; then
# Remove lock directory as it is still too old
rm -rf $U_DIR
fi
# Remove this short lock directory
rm -rf $U_DIR2
)
U_STATUS=$?
return $U_STATUS
}
####
second_of_now() {
second_of_day `date "+%y%m%d%H%M%S"`
}
####
#### Return which second of the date/time this is. The parameters must
#### be in the form "yymmddHHMMSS", no centuries for the year and
#### years before 2000 are not supported.
second_of_day() {
year=`printf "$1\n"|cut -c1-2`
year=`expr $year + 0`
month=`printf "$1\n"|cut -c3-4`
day=`printf "$1\n"|cut -c5-6`
day=`expr $day - 1`
hour=`printf "$1\n"|cut -c7-8`
min=`printf "$1\n"|cut -c9-10`
sec=`printf "$1\n"|cut -c11-12`
sec=`expr $min \* 60 + $sec`
sec=`expr $hour \* 3600 + $sec`
sec=`expr $day \* 86400 + $sec`
if [ `expr 20$year % 4` = 0 ]; then
bisex=29
else
bisex=28
fi
mm=1
while [ $mm -lt $month ]; do
case $mm in
4|6|9|11) days=30 ;;
2) days=$bisex ;;
*) days=31 ;;
esac
sec=`expr $days \* 86400 + $sec`
mm=`expr $mm + 1`
done
year=`expr $year + 2000`
while [ $year -gt 2000 ]; do
year=`expr $year - 1`
if [ `expr $year % 4` = 0 ]; then
sec=`expr 31622400 + $sec`
else
sec=`expr 31536000 + $sec`
fi
done
printf "$sec\n"
}
Verwendung wie folgt aus:
# Make sure that 2 operations don't happen at the same time
LockFile
# Make sure we get rid of our lock if we exit unexpectedly
trap "UnlockFile mine" 0
.
. Do what you have to do
.
# We need to remove the lock
UnlockFile mine
Sehr gute Frage . Ich kann mir keine Umstände vorstellen, unter denen dies passieren würde, es sei denn, zwei konkurrierende Prozesse wählten gleichzeitig denselben eindeutigen Dateinamen (was natürlich schlecht wäre). Könnte ein Workaround für sehr alte NFS-Fehler sein? – Celada
Müssen Sie Lockfiles über NFS erstellen?AFAIK sollten Sie 'flock()' oder 'lockf()' in den meisten Fällen verwenden können. – Hasturkun