我试图将(写入追加)附加到来自不同线程的文件(类似于日志记录),因此不需要进程间锁定。
我在fcntl.h中研究了flock,它说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();
是否可以使用互斥方法,因为仅在进程内只需要同步(或锁定)(仅多线程),
或者可以在fcntl.h中用flock实现代码吗?
答案 0 :(得分:1)
首先,您需要澄清多个线程与多个流程:
多线程:我建议使用互斥锁。您还可以通过将日志消息添加到内存缓冲区的末尾来提高效率,并且只使用互斥锁保护对该缓冲区的访问。然后,您可以使用另一个线程或一些常规维护功能将缓冲区刷新到文件,而不会在I / O进行时锁定其他线程,并且不会锁定文件。然后,对文件的访问既不受互斥锁的保护,也不受文件锁的保护,因为它只会被单个线程访问。
(由于您表明没有进程间通信,我建议采用这种方式。)
多个进程:您必须使用一些所有进程都可以看到的锁机制,例如你建议锁定文件。
两者:使用这两种机制。尝试仅在绝对最短时间内锁定文件。
侧节点:
多线程编程的第一条规则不是“使用互斥锁”,而是“尽量不要通过多线程访问数据”,甚至“尽量不要”使用多个线程,除非出于性能原因绝对必要' (例如,你总是可以在没有线程的情况下进行异步操作)。
答案 1 :(得分:1)
您可能不需要任何锁定。
在设置open()
标记的情况下进行O_APPEND
来电,如评论中@ Jean-BaptisteYunès所述。
然后使用单 write()
电话编写您的数据。 POSIX保证如果文件以追加模式打开,则单个write()
操作将是原子操作。 Per the POSIX standard:
如果设置了文件状态标志的O_APPEND标志,则为文件偏移量 应在每次写入之前设置为文件的末尾,并且否 干预文件修改操作应在更改之间进行 文件偏移和写操作。 [强调我的]
您唯一的问题是如何处理部分write()
- 其中单个write()
操作不会写入所有请求的数据。该标准要求每个write()
操作都是原子的 - 它不能保证写入34 MB的请求将导致写入整个34 MB。根据我的经验,部分write()
调用实际文件只是在write()
调用请求移动大量字节之前不会发生 - 我从未在任何单个IO上观察到部分write()
结果操作在1 MB以下的文件 - 我已经为很多大型组织完成了SAN安装和基准测试。
因此,如果将write()
调用限制在PIPE_BUF
或更少字节(在Linux上),几乎可以肯定可以避免所有锁定,并让内核内部锁定解决您的问题。
有关详细信息,请参阅以下内容:
Is file append atomic in UNIX?
请务必阅读那里的相关问题。