c ++ - mutex或flock fcntl.h只能锁定写操作

时间:2017-02-13 12:19:35

标签: c++ linux file mutex filelock

我试图将(写入追加)附加到来自不同线程的文件(类似于日志记录),因此不需要进程间锁定。

我在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实现代码吗?

2 个答案:

答案 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?

请务必阅读那里的相关问题。