linux — мьютекс или стадо fcntl.h для блокировки только операции записи

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

Я изучил flock в fcntl.h, и он говорит, что flock может делать гранулярную блокировку вместе с межпроцессным процессом, который не нужен в моей ситуации.

char* file = "newfile.txt";
int fd;
struct flock lock;

printf("opening %s\n", file);
fd = open(file, O_APPEND);
if (fd >= 0) {
memset(&lock, 0, sizeof (lock));
lock.l_type = F_WRLCK;
fcntl(fd, F_SETLKW, &lock);
//do my thing here
lock.l_type = F_UNLCK;
fcntl(fd, F_SETLKW, &lock);
close(fd);
}

Будут ли накладные расходы, поскольку он может выполнять гранулярную блокировку и межпроцессную блокировку? Что происходит при сбое программы при блокировке?

Мои нынешние предпочтения — мьютекс,

static std::mutex fileMutex;
fileMutex.lock();
//do my thing here
fileMutex.unlock();

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

или это нормально для реализации кода с flock в fcntl.h?

0

Решение

Вам может не понадобиться любой замок.

Сделай свой open() позвонить с O_APPEND флаг установлен, как @ Jean-BaptisteYunès упоминает в комментариях.

Затем запишите свои данные, используя не замужем write() вызов. POSIX гарантирует, что если файл открывается в режиме добавления, отдельный write() операции будут атомарными. По стандарту POSIX:

Если установлен флаг O_APPEND флагов состояния файла, то смещение файла
должен быть установлен в конец файла перед каждой записью и нет
промежуточная операция изменения файла должна происходить между изменениями
смещение файла и операция записи.
[акцент мой]

Ваша единственная проблема заключается в том, как справиться с частичным write() — где один write() операция не записывает все запрошенные данные. Стандарт требует каждого write() операция должна быть атомарной — это не гарантирует, что запрос на запись 34 МБ приведет к записи всех 34 МБ. По моему опыту, частичное write() вызовы реальных файлов просто не происходят, пока write() вызывает запрос на перемещение большого количества байтов — я никогда не наблюдал частичного write() результат любой операции ввода-вывода на файл менее 1 МБ — и я выполнил установку и тестирование SAN для довольно большого количества организаций.

Так что, если вы ограничиваете write() звонки под PIPE_BUF или меньше байтов (в Linux), вы почти наверняка можете избежать всех блокировок и позволить внутренней блокировке внутри ядра решить вашу проблему.

Для получения дополнительной информации см. Следующее:

Является ли файл append атомарным в UNIX?

Обязательно прочитайте вопросы, связанные оттуда, тоже.

1

Другие решения

Во-первых, вам нужно уточнить несколько потоков против нескольких процессов:

Несколько потоков: Я бы предложил использовать мьютекс. Вы также можете сделать это более эффективным, добавив сообщения журнала в конец буфера памяти, и вы только защищаете доступ к этому буферу, используя мьютекс. После этого вы можете создать другой поток или какую-либо обычную функцию обслуживания, чтобы сбросить буфер в файл, не блокируя другие потоки во время ввода-вывода и не блокируя файл. В этом случае доступ к файлу не будет защищен ни мьютексом, ни блокировкой файла, поскольку каждый будет доступен только одному потоку.

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

Несколько процессов: Вы должны использовать некоторый механизм блокировки, который виден всем процессам, например, файл блокирует, который вы предлагаете.

И то и другое: Используйте оба механизма. Попробуйте заблокировать файл только на абсолютное минимальное количество времени.

Боковой узел:

Первое правило многопоточного программирования — это не «использовать мьютекс», а «стараться не обращаться к данным несколькими потоками» или даже «стараться не использовать несколько потоков, если это абсолютно не необходимо из соображений производительности» (например, вы можете всегда обходиться без потоков для асинхронных операций).

1

По вопросам рекламы [email protected]