C语言 Linux 文件锁定



>问题:在Linux平台上创建新文件或覆盖现有文件,以便其他进程可以打开它进行读取。使用CreateFile可以执行以下操作:

CreateFile("blah.log", GENERIC_WRITE, FILE_SHARE_READ,
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

如果现有文件由具有类似标志的另一个进程打开,则此调用将无法覆盖该文件。

如何在 Linux 上实现类似的行为?假设所有程序都遵循咨询锁。

使用open和咨询flock锁定,编写者需要持有LOCK_EX独占锁。读取器不得持有任何锁,然后他们可能会看到文件被突然截断。

普通fopen可用于读者。对于表现良好的作家,

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <fcntl.h>
#include <stdio.h>
// never truncates
int fd = open("foo.log", O_CREAT|O_WRONLY /*or O_RDWR */, 0644 /* mode */);
if (flock(fd, LOCK_EX|LOCK_NB) != 0) {
perror("Locking failed - I am not an exclusive writer");
exit(1);
}
// I hold the exclusive lock - now, truncate the file to 0 bytes
ftruncate(fd, 0);

(为简洁起见,省略了其他错误检查(

如果您希望从那里对文件使用<stdio.h>例程,您可以使用fdopen

// "w" will not truncate!
FILE *f = fdopen(fd, "w"); // or `r+` for O_RDWR...

请注意,读取器不得在文件上设置LOCK_SH锁,否则编写器无法打开该文件。

您正在寻找flocklockf功能:)

其中大部分都是基于man 2 flockman lockf,所以我衷心推荐阅读它。

这是来自man lockf

#include <unistd.h>
int lockf(int fd, int cmd, off_t len);

描述

在打开的文件的某个部分应用、测试或删除 POSIX 锁定。 该文件由 fd 指定,一个打开的文件描述符 写作,CMD的行动,该部分包括 字节位置位置。POS+len-1 如果 len 为正,则 pos-len..POS-1 如果 len 为负数,则 pos 是当前文件 位置,如果 len 为零,则截面从 当前文件位置到无穷大,包括当前和将来的文件结束位置。 在所有情况下,该部分都可能扩展 过去的当前文件结尾。

在 Linux 上,lockf()只是 fcntl(2( 锁定之上的一个接口。 许多其他系统以这种方式实现lockf(), 但请注意,POSIX.1 留下了 未指定lockf()fcntl(2)锁。 可移植应用程序可能应避免混合调用这些接口。

有效操作如下:

  • F_LOCK在文件的指定部分设置独占锁。 如果此部分(部分(已被锁定,则调用将阻止,直到释放上一个锁定。 如果此部分与较早锁定的部分重叠,则两者将合并。 一旦持有锁的进程关闭文件的某些文件描述符,文件锁就会释放。 子进程不会继承这些锁。
  • F_TLOCKF_LOCK相同,但如果文件已锁定,则调用永远不会阻止并返回错误。
  • F_ULOCK解锁文件的指定部分。 这可能会导致锁定部分拆分为两个锁定部分。
  • F_TEST测试锁:如果指定的部分被此进程解锁或锁定,则返回 0;如果另一个进程持有锁,则返回-1,将errno设置为EAGAIN(在其他一些系统上EACCES(。

但这只是一个独占锁,所以不太适合单写机、多读卡器的情况。

我会看看 unix 套接字 (man unix(。它们的工作方式类似于文件或套接字(它们是套接字,但您可以在它们上使用 file-io 函数(,并且尝试关联其他人已经拥有的套接字(可以像普通文件一样驻留在文件系统中(将失败。

老实说,您尝试做的事情听起来很像IPC(进程间通信(,这很好 - 但您可能想看看simlper共享内存协调!shmget和类似的东西将允许您以非常类似文件的方式打开内容,并且您可以以高性能直接在进程之间交换数据,而不会招致将数据写入磁盘的损失。(非常相似地,您可以将实际文件映射到内存中做同样的事情,但这并不能解决锁定问题(。

但是:这些是解决IPC问题的非常低层次的方法。我建议实际使用 IPC 库。有很多可以满足不同系统的需求 - 从大型集群类系统的MPI,到非常好的基于套接字的系统,或类似套接字的灵活系统(想到zeroMQ(。

最新更新