从两个线程同时读取文件描述符

jar*_*ero 5 multithreading posix file-descriptor

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

  2. 我做了一些搜索,但是什么也没找到,尽管很多人都问类似的问题,关于同时读/写套接字fd(意思是在写其他线程时读,而不是在读其他线程时读)。我还阅读了一些手册页,但对我的问题没有明确的答案。

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

编辑:我做了一些研究,发现只是直接调用通过syscall读取不会更改任何内容。内核代码似乎进行了一些同步处理,但是我不太了解(read_write.c)

jar*_*ero 6

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

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

  • 然而,“read()”对常规文件和符号链接的行为是已定义的。看我的回答。 (2认同)

hag*_*llo 5

关于并发访问单个文件描述符(即从多个线程甚至进程),我将引用POSIX.1-2008(IEEE Std 1003.1-2008),第2.9.7小节Thread Interactions with Regular File Operations

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

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

[…] 读() […]

如果两个线程分别调用这些函数中的一个,则每个调用要么看到另一个调用的所有指定效果,要么不看到它们。[…]

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

@jarero 引用:

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

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