Как синхронизировать доступ к файлу на linux?

Пишу программу на C++ для linux, она вызывает уже готовую программу, которую я не могу менять, эта программа создаёт определённый файл. Программа работает в отдельном потоке в интерактивном режиме из терминала и не завершается после генерации файла.

Я ожидаю появления файла в своей программе, пытаясь открыть его. И если предыдущая программа не успела дописать файл, я получаю неполные данные.

Есть ли способ узнать, закрыли ли файл остальные потоки, чтоб можно было корректно прочитать все записанные данные?

Возможно есть событие создания файла, чтоб не ждать его появления в цикле?

Есть ли событие закрытия файла другим потоком?

Пример моей программы, ожидающей файл

remove("image.raw");
pid = fork();
switch (pid) {
  case -1:
    return;
  case 0:
    execl("program", "program", NULL);
    return;
}
std::ifstream in;
do {
  usleep(100000);
  in.open("image.raw", std::ios::in | std::ios::binary | std::ios::ate);
} while (!in.is_open());
in.read(reinterpret_cast<char*>(data), size);
in.close();

eri предложил использовать inotify, вот пример программы с использованием этой библиотеки

test_inotify.c

#include <sys/inotify.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <fcntl.h>
#define BUF_LEN (sizeof(struct inotify_event) + NAME_MAX + 1)

int main() {
    int f = creat("/tmp/image.raw", S_IRWXU);
    if (f == -1) {
      perror("creat");
    }
    if (close(f) == -1) {
      perror("close");
    }

    int fd = inotify_init1(IN_CLOEXEC);
    if (fd == -1) {
      perror("inotify_init");
      return 1;
    }
    int wd = inotify_add_watch(fd, "/tmp/image.raw", IN_CLOSE_WRITE | IN_ONESHOT);
    if (wd == -1) {
      perror("inotify_add_watch");
      return 1;
    }

    pid_t pid = fork();
    switch (pid) {
      case -1:
        perror("fork");
        return 0;
      case 0:
        if (execl("program", "program", NULL) == -1) {
          perror("execl");
        }
        return 0;
    }

    char buf[BUF_LEN] __attribute__ ((aligned(8)));
    ssize_t num_read = read(fd, buf, BUF_LEN);
    if (num_read == -1) {
      perror("read");
      return 1;
    }
    printf("File image.raw closed\n");

    inotify_rm_watch(fd, wd);
    close(fd);

    return 0;
}

program.c

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

int main() {
  int f = open("/tmp/image.raw", O_CREAT | O_RDWR);
  write(f, "test", 4);
  close(f);
  return 0;
}

build.sh

#!/bin/sh

g++ test_inotify.c -o test_inotify
g++ program.c -o program

Ответы (1 шт):

Автор решения: eri

Для линукс используй INOTIFY https://linux.die.net/man/7/inotify и жди IN_CLOSE_WRITE

Пример на Си можно встроить в плюсы

#include <sys/inotify.h>
#define BUF_LEN (10 * (sizeof(struct inotify_event) + NAME_MAX + 1))

int main(){

    int inotifyFd, wd, done;
    char buf[BUF_LEN] __attribute__ ((aligned(8)));
    ssize_t numRead;
    char *p;
    struct inotify_event *event;
    
    done = 0;
    
    wd = inotify_add_watch(inotifyFd, "/tmp/", IN_CLOSE_NOWRITE|IN_CLOSE_WRITE);

    do {  
        numRead = read(inotifyFd, buf, BUF_LEN);
        for (p = buf; p < buf + numRead; ) {
            event = (struct inotify_event *) p;
            if ( strcmp(event->name, "image.raw") == 0) {
                done = 1;
                printf("File image.raw closed\n");
                break; 
            }
            p += sizeof(struct inotify_event) + event->len;
        };
    } while ( done==0 );
    return 0;
}

.. не проверил, может где опечатался.

→ Ссылка