linux系统多线程写入文件如何保证同步

首先,所有的系统调用都是原子性的。这句话来自TLPI:

"All system calls are executed atomically. By this, we mean that the kernel guarantees that all of the steps in a system call are completed as a single operation, without being interrupted by another process of thread."

太好了!于是当两个线程或进程在同一时间写同一文件时,我们可以肯定他们的数据不会交错插入。这使调用write(2)不需要互斥锁,而且还能保证原子性,因为内核已经帮我们做到那个了。

但是还有一个问题,一般写文件时,你需要找到你想插入的具体的位置,然后再进行真正的写入操作。不幸的是,这会涉及到两个系统调用,lseek(2)和write(2).他们各自是原子性的,但是两个操作作为一个整体就不是原子性的。让我们来证明下:

用下面的伪代码表示写文件的过程:

lseek(fd,0,SEEK_END);// seek to the end of the file

write(fd,"log message",len);// perform the write

在多线程环境下,这种操作是不安全的。通过这两个系统调用不能保证原子性,例如下面的情况:

d'oh 线程A不在指向文件的真正末尾位置,它指向文件先前的默认位置,线程B写入信息的位置。当线程A写入文件时,可能被线程B写入的信息覆盖。

通过这种方法写文件,有可能会丢失数据。

但是还有一种方法。

为了能保证seek和write两个操作发生的原子性,你可以设置O_APPEND标志,当你在打开一个文件时。然后,任何往文件追加的写操作都能保证是原子性的。这正是我们在写要共享日志文件时想要的情况。Logger和MonoLogger都是用这个标志来打开文件。

open(filename,(FILE::WRONLY|FILE::APPEND))

因此MonoLogger可以原子性的追加到日志系统,而不需要互斥信号。


转载:https://www.jianshu.com/p/b5a731940ff9

posted @ 2020-01-07 14:29  朱子威  阅读(1695)  评论(1编辑  收藏  举报