在 /dev 中直接写入设备时,我打开一个文件描述符并执行 UNIX write(),然后执行 read()。我是否可以让多个线程在同一个文件描述符上执行此 write()/read() 序列,并且如果两个线程同时进入 write() 函数,则不会得到混乱的数据?
对 std 文档的引用将非常有帮助。我一直无法找到任何东西。有人提到这样的操作在内核中是原子的,但我持怀疑态度。
此外,为了澄清这是 /dev 中的一个文件,因此任何关于“文件指针”概念在此处应用多远的见解也很有帮助。
在 /dev 中直接写入设备时,我打开一个文件描述符并执行 UNIX write(),然后执行 read()。我是否可以让多个线程在同一个文件描述符上执行此 write()/read() 序列,并且如果两个线程同时进入 write() 函数,则不会得到混乱的数据?
对 std 文档的引用将非常有帮助。我一直无法找到任何东西。有人提到这样的操作在内核中是原子的,但我持怀疑态度。
此外,为了澄清这是 /dev 中的一个文件,因此任何关于“文件指针”概念在此处应用多远的见解也很有帮助。
我将假设您指的是通用字符设备(例如 tty),因为您并不具体。据我所知,每个 fd 类型的操作(例如 read()/write())都直接映射到对驱动程序的调用。
因此,驱动程序将作为一个整体接收每个 write() 的数据块,并且在完成之前看不到下一个的数据(例如,数据排队等待传输)。
但是,如果驱动程序没有立即消耗整个数据块(即 write() 返回的字节数少于指定的字节数,则无法保证线程能够在另一个线程之前再次写入剩余的数据执行不同的 write()。
此外,正如 Johnathan Leffler 所指出的,如果您将标准 I/O 与进程级缓冲一起使用,那么所有的赌注都将落空。
底线,如果您使用直接 fd 写入,则每次写入将直接映射到一个驱动程序函数调用。从那里开始,由驱动程序决定 write 是否是原子的。
编辑: wlformyd 提出了在多个处理器上的多个线程之间锁定的问题。据我所知,FD 上没有锁定,事实上,这将是无效的,因为可以使用多个 FD 访问同一设备。
我相信由驱动程序本身进行锁定以防止争用内部队列和/或硬件。从这个意义上说,在多处理器系统上,内核不会阻止多个同时访问驱动程序的写例程。但是,正确编写的驱动程序应该执行锁定以防止在两个写入调用之间混合输出。
文件指针(FILE *fp
例如 )是用户端代码中位于函数调用(例如write()
)之上的一层。访问fp
由线程环境中的锁控制(您不能让线程同时修改相同的结构)。
在内核内部,我希望文件描述符(和/或“打开文件描述”)上有一个锁,以防止它同时被两个线程使用。
您可以查找 POSIX 规范
以了解有关锁定等的更多信息——至少对于 POSIX 兼容的实现read()
。
getchar_unlocked()
请注意,POSIX 仍然使用 C99。因此,它不了解 C11 线程设施。C11 标准没有read()
et al(使用文件描述符的文件 I/O),因此它没有说明此类系统调用。它也不提供一个getchar_unlocked()
或任何它的亲属。
警告:我已经有一段时间没有使用内核了,但这是它过去的工作方式。
对于磁盘文件:
你能以追加模式打开文件,写入块大小<= BLKSIZE
吗?
足够小的块大小保证,在 POSIX 环境中,在 POSIX 环境中原子写入(实际上,限制可能大于 BLKSIZE ......我懒得四处寻找替代符号)。
将保证寻求到文件的末尾...对于支持寻求的设备。结合原子写入,你应该是金色的。
假设某些“外来”信息可能跟随它,每个缓冲区必须独立存在。
对于 ttys:
附加模式在这里没有意义。和以前一样,但注意行尾变得更加重要。这非常不适用于读取。ttys 视为控制序列的代码也会使您感到困惑,即使序列启用跨块拆分的模式也是如此。
对于其他设备:
在这里可能会变得棘手。取决于设备。