C read() 线程安全吗?

tmo*_*e82 4 c linux multithreading file thread-safety

我正在编写一个程序,其中多个线程可能同时从文件中读取。没有线程写入该文件,但它们可能各自将其内容复制到单独的内存段。

为了实现这一点,我需要使用一个 API,为我想要读取的文件提供一个文件描述符。我正在使用 C 函数读取文件的块read。手册页说:“成功时,返回读取的字节数(零表示文件末尾),并且文件位置将按此数字前进。” 不过,我找不到任何关于文件位置的前进是否是线程安全的明确信息。

假设我有线程 T1 和线程 T2 一次读取文件的 1 个字节。如果read()是线程安全的,我期望以下内容:

T1: read() => file position == 1
T2: read() => file position == 1
T1: read() => file position == 2
T2: read() => file position == 2
...
Run Code Online (Sandbox Code Playgroud)

但我担心如果它不是线程安全的,那么可能会发生以下情况:

T1: read() => file position == 1
T2: read() => file position == 2
T1: read() => file position == 3
T2: read() => file position == 4
...
Run Code Online (Sandbox Code Playgroud)

如果有帮助,每个线程将使用相同的文件描述符。换句话说,它是使用open(). 然后,正在读取文件的线程根据客户端请求获取该文件描述符。如果每个线程都存储自己的有关文件位置的信息,那么应该没问题。我只是找不到任何有关文件位置的信息以及在哪里read()找出它是什么的信息。

R..*_*R.. 5

read它本身是线程安全的,但这并不一定意味着您想要用它做的事情是线程安全的。根据 POSIX(2.9.7 线程与常规文件操作的交互):

当以下所有函数在常规文件或符号链接上操作时,在 POSIX.1-2008 中指定的效果中,彼此之间应是原子的:

...

read在下面的列表中。)

除此之外,这意味着读取数据和前进当前文件位置相对于彼此而言是原子的,并且读取的每个字节将被读取一次。然而,还有其他一些考虑因素可能会让事情变得复杂,特别是:

  • 短读:read(fd, buf, n)不需要读取n字节。它可以读取 1 到n字节之间的任何位置,当您再次调用它来读取剩余部分时,第二次读取相对于第一次读取不再是原子的。

  • 其他文件类型:POSIX 仅保证read常规文件以及可能其他一些类型的原子性。像 Linux 这样的特定系统可能有更强的保证,但我会谨慎。

最好使用该pread函数(您可以指定要读取的文件偏移量,而无需查找该位置,并且结果文件位置保持不变)或对文件访问执行锁定以避免此类问题。