Блокировка файлов. Что делать в первую очередь? Разблокировать или закрыть?

Я открываю, а потом закрываю. Один процесс добавляет записи ABCDEFGHIJ. Другой процесс читает тот же файл и записывает ZZZZ. Обычный файл должен быть ZZZZ ABCDEFGHIJ

Но только однажды я увидел следующее: ZZZZEFGHIJ Итак, запись ABCDEFGHIJ повреждена с помощью ZZZZ.

Кажется, моя блокировка не работает. Но я проверил это. Один процесс действительно ждет другого. Может ли другой процесс записывать в файл между открытием и блокировкой? Или между разблокировкой и закрытием?

Код ниже

int MyOpenWrite(char *name,int flags) {
int fd
fd = open(name,flags,S_IREAD|S_IWRITE|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
LockFile(fd);
return fd;
 }

int WriteFile(char *name, char *data) {
...
fd = MyOpenWrite(fullName,O_CREAT|O_WRONLY|O_TRUNC);
write(fd,data,strlen(data));
UnLockFile(fd);
close(fd);
}

int ReadFile(char *name, char *data, int maxLength) {
fd = open(name,O_RDONLY);
LockFile(fd);
...
UnLockFile(fd);
close(fd);
}

int AppendFile(char *name, char *data) {
fd = MyOpenWrite(fullName,O_WRONLY|O_APPEND);
...
len=write(fd,data,strlen(data));
UnLockFile(fd);
close(fd);
 }

int LockFile(int fd) {
struct flock    lock;
lock.l_type = F_WRLCK;
lock.l_start = 0;
lock.l_whence = SEEK_SET;
lock.l_len = 0;
return fcntl(fd,F_SETLKW,&lock);
}

int UnLockFile(int fd)  {
struct flock    lock;
lock.l_type = F_UNLCK;
lock.l_start = 0;
lock.l_whence = SEEK_SET;
lock.l_len = 0;
return fcntl(fd,F_SETLKW,&lock);
}

Я попытался закрыть (fd) разблокировку (fd). Кажется, это работает. Но в любом случае есть задержка между открытием и блокировкой. Спасибо.


person nms    schedule 19.03.2013    source источник
comment
Возможно, вам следует сбросить файл перед его разблокировкой?   -  person Lily Ballard    schedule 19.03.2013
comment
Хм. Сомневаюсь. Флеш просто пишет на HDD. Я думаю, что если файл не записывается на жесткий диск, а второй процесс его читает, он должен читать его из кэша, а не с жесткого диска.   -  person nms    schedule 19.03.2013
comment
Нет, fflush-запись файла фактически записывает файл.   -  person Basile Starynkevitch    schedule 19.03.2013
comment
fflush очищает буферы stdio. Это не гарантирует, что биты будут физически записаны ядром на диск. Вам нужно fsync для этого.   -  person rra    schedule 19.03.2013
comment
У вас нет гарантии, что процессы A и B совместно используют кеш для файлового ввода-вывода.   -  person user7116    schedule 19.03.2013
comment
он использует запись, а не буферизованную fwrite.   -  person LtWorf    schedule 19.03.2013


Ответы (1)


Пока вы не write(2) к файлу (после разблокировки), не имеет значения, разблокируете ли вы его сначала или close(2) сначала.

Однако close(2)-ing файл разблокирует его (по крайней мере, если ни один другой процесс не использует тот же дескриптор открытого файла).

См. fcntl(2), в котором говорится

As well as being removed by an explicit F_UNLCK, record locks are
automatically released when the process terminates or if it closes any
file descriptor referring to a file on which locks are held.

дополнения: следует проверять на наличие сбоев

Обратите внимание, что в вашем коде отсутствует проверка ошибок. Почти каждая библиотечная функция или системный вызов, в частности fcntl, read, write, может дать сбой (и установить errno для отображения, например, perror или strerror(errno) в каком-либо журнале или печати). Вы не проверяете успех или неудачу fcntl в своих функциях LockFile или UnlockFile, и вы не проверяете ни того, ни другого в вызывающей программе.

person Basile Starynkevitch    schedule 19.03.2013
comment
Я понимаю. А что не так в моем замке, если он не работает? - person nms; 19.03.2013
comment
Вы должны проверить на наличие сбоев, как я только что добавил. - person Basile Starynkevitch; 19.03.2013