Estoy usando flock () para mutexes con nombre entre procesos (es decir, algún proceso puede decidir mantener un bloqueo en “some_name”, que se implementa bloqueando un archivo llamado “some_name” en un directorio temporal:
lockfile = "/tmp/some_name.lock";
fd = open(lockfile, O_CREAT);
flock(fd, LOCK_EX);
do_something();
unlink(lockfile);
flock(fd, LOCK_UN);
El archivo de bloqueo debe eliminarse en algún momento para evitar llenar el directorio temporal con cientos de archivos.
Sin embargo, hay una condición de carrera obvia en este código; ejemplo con los procesos A, B y C:
A opens file
A locks file
B opens file
A unlinks file
A unlocks file
B locks file (B holds a lock on the deleted file)
C opens file (a new file one is created)
C locks file (two processes hold the same named mutex !)
¿Hay alguna manera de eliminar el archivo de bloqueo en algún momento sin introducir esta condición de carrera?

usuario2769258
Lo siento si respondo a una pregunta muerta:
Después de bloquear el archivo, abra otra copia del mismo, haga clic en ambas copias y verifique el número de inodo, así:
lockfile = "/tmp/some_name.lock";
while(1) {
fd = open(lockfile, O_CREAT);
flock(fd, LOCK_EX);
fstat(fd, &st0);
stat(lockfile, &st1);
if(st0.st_ino == st1.st_ino) break;
close(fd);
}
do_something();
unlink(lockfile);
flock(fd, LOCK_UN);
Esto evita la condición de carrera, porque si un programa mantiene un bloqueo en un archivo que todavía está en el sistema de archivos, cualquier otro programa que tenga un archivo sobrante tendrá un número de inodo incorrecto.
De hecho, lo probé en el modelo de máquina de estado, usando las siguientes propiedades:
Si P_i tiene un descriptor bloqueado en el sistema de archivos, entonces no hay ningún otro proceso en la sección crítica.
Si P_i está después de la estadística con el inodo correcto o en la sección crítica, tiene el descriptor bloqueado en el sistema de archivos.

Guido U Draheim
- En Unix, es posible eliminar un archivo mientras está abierto: el inodo se mantendrá hasta que todos los procesos hayan finalizado y lo tengan en su lista de descriptores de archivos.
- En Unix, es posible verificar que un archivo se eliminó de todos los directorios al verificar el recuento de enlaces a medida que se vuelve cero
Entonces, en lugar de comparar el valor ino de las rutas de archivo antiguas/nuevas, simplemente puede verificar el recuento de nlink en el archivo que ya está abierto. Asume que es solo un archivo de bloqueo efímero y no un recurso o dispositivo mutex real.
lockfile = "/tmp/some_name.lock";
for(int attempt; attempt < timeout; ++attempt) {
int fd = open(lockfile, O_CREAT, 0444);
int done = flock(fd, LOCK_EX | LOCK_NB);
if (done != 0) {
close(fd);
sleep(1); // lock held by another proc
continue;
}
struct stat st0;
fstat(fd, &st0);
if(st0.st_nlink == 0) {
close(fd); // lockfile deleted, create a new one
continue;
}
do_something();
unlink(lockfile); // nlink :=0 before releasing the lock
flock(fd, LOCK_UN);
close(fd); // release the ino if no other proc
return true;
}
return false;

MvG
Si usa estos archivos solo para bloquear y en realidad no escribe en ellos, le sugiero que trate la existencia de la entrada del directorio como una indicación de un bloqueo retenido y evite usar flock
en total.
Para hacerlo, debe construir una operación que cree una entrada de directorio e informe un error si ya existe. En Linux y con más sistemas de archivos, pasando O_EXCL
para open
funcionará para esto. Pero algunas plataformas y algunos sistemas de archivos (en particular, NFS más antiguos) no admiten esto. los página man para open
por lo que sugiere una alternativa:
Programas portátiles que desean realizar un bloqueo atómico de archivos mediante un archivo de bloqueo y necesitan evitar la dependencia de la compatibilidad con NFS para O_EXCL
puede crear un archivo único en el mismo sistema de archivos (por ejemplo, incorporando nombre de host y PID) y usar link
(2) para hacer un enlace al archivo de bloqueo. Si link
(2) devuelve 0, el bloqueo es exitoso. De lo contrario, utilice stat
(2) en el archivo único para verificar si su recuento de enlaces ha aumentado a 2, en cuyo caso el bloqueo también es exitoso.
Esto parece un esquema de bloqueo que está documentado oficialmente y, por lo tanto, indica un cierto nivel de soporte y sugerencia de mejores prácticas. Pero también he visto otros enfoques. bzr por ejemplo, utiliza directorios en lugar de enlaces simbólicos en la mayoría de los lugares. citando de su código fuente:
Un bloqueo está representado en el disco por un directorio de un nombre particular, que contiene un archivo de información. La toma de un bloqueo se realiza cambiando el nombre de un directorio temporal en su lugar. Usamos directorios temporales porque para todos los transportes y sistemas de archivos conocidos, creemos que exactamente un intento de reclamar el bloqueo tendrá éxito y los demás fallarán. (Los archivos no funcionarán porque algunos sistemas de archivos o transportes solo tienen renombrar y sobrescribir, lo que dificulta saber quién ganó).
Una desventaja de los enfoques anteriores es que no se bloquearán: un intento fallido de bloqueo dará como resultado un error, pero no espere hasta que el bloqueo esté disponible. Tendrá que sondear el bloqueo, lo que podría ser problemático a la luz de la contención de bloqueo. En ese caso, es posible que desee alejarse aún más de su enfoque basado en el sistema de archivos y utilizar implementaciones de terceros en su lugar. Pero ya se han hecho preguntas generales sobre cómo hacer mutexes de ipc, por lo que le sugiero que busque [ipc] [mutex]
y echa un vistazo a los resultados, este en particular. Por cierto, estas etiquetas también pueden ser útiles para tu publicación.
El problema es que está tratando de implementar una estrategia de bloqueo de grano fino (los archivos representan recursos), pero tiene una disputa sobre un recurso de grano grueso compartido (el sistema de archivos). O necesita un bloqueo global en el directorio de archivos de bloqueo antes de actualizar sus bloqueos detallados o rediseñar su estrategia de bloqueo por completo.
– jxh
17 de julio de 2013 a las 19:57
¿Puedes elaborar tu necesidad? Por ejemplo, ¿por qué no hacer que los programas usen 1 nombre de archivo conocido si todos están bloqueando el mismo recurso conceptual?
– Arte Swri
17/07/2013 a las 20:51