10
  1. 我的问题:在 Linux(和 FreeBsd 中,通常在 UNIX 中)是否可以/合法地从两个线程同时读取单个文件描述符?

  2. 我做了一些搜索,但一无所获,尽管很多人同时询问有关从/向套接字 fd 读取/写入的问题(意思是在其他线程正在写入时读取,而不是在其他线程正在读取时读取)。我也阅读了一些手册页,但对我的问题没有明确的答案。

  3. 为什么我问它。我试图实现一个简单的程序来计算标准输入中的行数,比如 wc -l。我实际上是在测试我自制的 C++ io 引擎的开销,发现 wc 快了 1.7 倍。我削减了一些 C++ 并接近 wc 速度但没有达到它。然后我尝试了输入缓冲区的大小,对其进行了优化,但 wc 显然还是快了一点。最后我创建了 2 个并行读取相同 STDIN_FILENO 的线程,这终于比 wc 快了!但是行数变得不正确......所以我想一些垃圾来自意外的读取。内核不关心读取什么进程吗?

编辑:我做了一些研究,发现直接通过系统调用调用 read 并没有改变任何东西。内核代码似乎做了一些同步处理,但我不太了解(read_write.c)

4

3 回答 3

6

这是未定义的行为,POSIX 说:

read() 函数应尝试从与打开的文件描述符 fildes 关联的文件中读取 nbyte 字节到由 buf 指向的缓冲区中。未指定同一管道、FIFO 或终端设备上的多个并发读取的行为。

于 2011-03-17T11:35:40.050 回答
5

关于同时访问单个文件描述符(即从多个线程甚至进程),我将引用POSIX.1-2008 (IEEE Std 1003.1-2008),第2.9.7 节与常规文件操作的线程交互

2.9.7 线程与常规文件操作的交互

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

[…] 读() […]

如果两个线程各自调用这些函数之一,则每个调用要么看到另一个调用的所有指定效果,要么一个都看不到。[…]

乍一看,这看起来相当不错。但是,我希望您在对常规文件或符号链接进行操作时不要错过限制。

@jarero 引用:

未指定同一管道、FIFO 或终端设备上的多个并发读取的行为。

因此,我们隐含地同意,我假设:这取决于您正在阅读的文件的类型。您说,您从 STDIN 读取。好吧,如果你的 STDIN 是一个普通文件,你可以使用并发访问。否则你不应该。

于 2019-08-18T20:32:33.180 回答
4

当与描述符 (fd) 一起使用时,read() 和 write() 依赖于 fd 的内部状态来了解将发生读取和写入的“当前偏移量”。因此,它们不是线程安全的。

为了允许多个线程同时使用单个描述符,提供了 pread() 和 pwrite()。使用这些接口,指定了描述符和所需的偏移量,因此不使用描述符中的“当前偏移量”。

于 2013-01-08T18:43:22.810 回答