Безопасно ли двум потокам записывать идентичный контент в один и тот же файл? - PullRequest
1 голос
/ 21 апреля 2020

Предположим, что в программе имеется механизм кэширования, в котором в конце какого-либо конкретного вычисления c программа записывает вывод этого вычисления на диск, чтобы избежать его повторного вычисления позже, когда программа будет перезапущена. Это делается для большого числа вычислений и сохраняет каждый вывод в отдельных файлах (по одному на каждое вычисление, имена файлов определяются путем хеширования параметров вычислений). Данные записываются в файл со стандартными потоками C ++:

    void* data = /* result of computation */;
    std::size_t dataSize = /* size of the result in bytes */;
    std::string cacheFile = /* unique filename for this computation */;

    std::ofstream out(cacheFile, std::ios::binary);
    out << dataSize;
    out.write(static_cast<const char *>(data), dataSize);

Расчет является детерминированным c, поэтому данные, записанные в данный файл, всегда будут одинаковыми.

Вопрос : безопасно ли нескольким потокам (или процессам) делать это одновременно, для одного и того же вычисления и с одним и тем же выходным файлом? Не имеет значения, если некоторые потоки или процессы не могут записать файл, если хотя бы одна из них успешно выполняется, и пока все программы остаются в допустимом состоянии.

В ручных тестах, которые я запускал, нет Произошел сбой программы или повреждение данных, и файл всегда создавался с правильным содержимым, но это может зависеть от платформы. Для справки: в нашем конкретном случае c размер данных варьируется от 2 до 50 килобайт.

Ответы [ 2 ]

2 голосов
/ 21 апреля 2020

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

Это условие гонки, когда несколько потоков попробуйте записать в тот же файл, чтобы вы могли получить поврежденный файл. Нет никакой гарантии, что ofstream::write является атомом c и зависит от конкретной файловой системы.

Надежное решение вашей проблемы (работает как с несколькими потоками, так и / или процессами):

  1. Запись во временный файл с уникальным именем в целевом каталоге (чтобы временные и конечные файлы находились в одной файловой системе для rename, чтобы не перемещать данные).
  2. rename временный файл с его окончательным именем. Он заменяет существующий файл, если он там есть. Непереносимый renameat2 более гибкий.
0 голосов
/ 21 апреля 2020

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

Операционные системы предоставляют специальные функции для блокировки файлов, которые гарантированно будут иметь атомы c (например, lockf на Linux или LockFile (Ex) на Windows). Вы можете проверить их.

...