Fondo

En mi programa C, estoy leyendo un archivo línea por línea.

FILE *file = fopen("config.txt", "r");

if (file)
{
    char *line;
    size_t length;
    size_t read;
    int test_case_number = 0;

    while ((read = getline(&line, &length, file)) != -1)
    {
        printf("%s", line);
    }
}
else
{
    fputs("The provided <PATH_TO_CONFIG FILE> does not exist.\n\n");
    exit(1);
}

Problema

Sin embargo, mientras estoy leyendo este archivo, quiero evitar que cualquier otro proceso escriba a config.txt mientras se está leyendo. ¿Cómo puedo hacer esto?

3
Nicholas Adamou 8 dic. 2019 a las 20:16

2 respuestas

La mejor respuesta

Si tiene que "defenderse" de sus propios procesos o procesos de "buen comportamiento", entonces desea utilizar flock:

   fp = fopen(fileName, fileMode);
   if (fp != NULL) {
       flock(fileno(fp), LOCK_EX);
       ...
       fclose(fp); fp = NULL;
   }

Pero esos bloqueos son solo consultivos , es decir, cualquier otro proceso puede elegir ignorarlos . O no molestarse en comprobar. Acabo de intentar crear un archivo, abrirlo y bloquearlo con LOCK_EX, y luego dormir durante 60 segundos. Durante ese tiempo, otro proceso fue libre de hacer lo que quisiera con el archivo (Linux, Ubuntu 18.04-LTS).

Pero si necesita el bloqueo obligatorio , eso no es algo que esté disponible en todas las plataformas ya que el núcleo tiene que cooperar. Aquí encontrará una descripción y un ejemplo de cómo el limitado soporte de bloqueo obligatorio en Linux.

Por otro lado, en Windows esto es automático:

Windows establece de forma predeterminada el bloqueo automático y obligatorio de archivos. UNIXes predeterminado a manual, bloqueo cooperativo de archivos. En ambos casos, los valores predeterminados pueden anularse, pero en ambos casos generalmente no lo son. (fuente).

Una solución alternativa puede ser cambiar temporalmente el nombre del archivo en el que se está trabajando por un nombre único, posiblemente creando un archivo vacío con el nombre anterior en su lugar, y luego renombrándolo una vez que haya terminado; o copiando el archivo como arriba, dejando una copia para que otros programas lo lean. La negación de escritura también se puede lograr cambiando los permisos del archivo. Estas soluciones requieren manejar algunos casos extremos, p. Ej. donde su proceso falla o la máquina se cuelga antes de volver a poner las cosas como estaban.

1
LSerni 8 dic. 2019 a las 17:33

En Linux, puede usar flock () (enfoque por mí):

Aplicar o eliminar un bloqueo de aviso en un archivo abierto.

LOCK_EX Coloque un bloqueo exclusivo . Solo un proceso puede contener un bloqueo exclusivo para un archivo dado en un momento dado.

Sin embargo, deberá abrir su archivo con open(), en lugar de fopen().

Pregunta con un ejemplo abstracto: flock (): ¿eliminar el archivo bloqueado sin condición de carrera? O consulte este ejemplo.

IMPORTANTE: Como @JonathanLeffler comentó "Tenga en cuenta el término" bloqueo de aviso ", eso significa que si el proceso de escritura no prueba el bloqueo, podrá escribir. En sistemas similares a POSIX, puede usar flock() o lockf() o fcntl() bloqueando el descriptor de archivo a través de fileno(fp) ".

1
gsamaras 8 dic. 2019 a las 17:33