2017-02-13 17 views
0

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

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

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?

+1

открыт в режиме O_APPEND! –

ответ

1

Возможно, вам не нужен любой блокировка.

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

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

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

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

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

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

Is file append atomic in UNIX?

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

+0

Что делать, если запись превышает PIPE_BUF, размер может быть легко превышен. Теперь я могу думать только о мьютексе с потоком записи. –

+0

@ fury.slay Поскольку вы работаете в Linux, если вы контролируете всю свою платформу - в том числе файловую систему, на которую будете писать - вам придется проверять вещи и выяснять, каков фактический предел. См. Http://stackoverflow.com/questions/10650861 Вы были в Solaris или AIX, вы почти наверняка будете в безопасности до 1 МБ за операцию записи (обратите внимание на ссылку, что на ZFS - из Solaris - каждая запись() 'был атомарным ...) С более поздними версиями Linux вы можете * быть. –

+0

Я могу проверить свою систему, но приложение в комплекте для запуска на разных типах Linux-пользователей, поэтому у меня не будет никакой гарантии безопасности. Поправьте меня, если я ошибаюсь. –

1

Прежде всего, необходимо уточнить несколько потоков vs. нескольких процессов:

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

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

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

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

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

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

+0

Я упомянул, что существует ** отсутствие межпроцессного взаимодействия ** (нет многопроцессорных процессов) –

+0

, поэтому вы предполагаете, что в случае многопоточного mutex намного лучше, чем стая, и что нет необходимости идти на стаю, не так ли? –

+0

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