c-向设备发送数据时,UNIX读取()/写入()的原子性



在/dev/中直接写入设备时,我打开一个文件描述符,然后执行UNIX写()和读()。我可以让多个线程在相同的文件描述符上执行这个write()/read()序列吗?如果两个线程同时进入write(?

参考std文档会非常有帮助。不过我什么也没找到。有人提到这样的操作在内核中是原子操作,但我对此持怀疑态度。

此外,为了澄清这是/dev/中的一个文件,因此了解"文件指针"概念在这里的应用程度也很有帮助。

文件指针(例如FILE *fp)是位于函数调用(如write())上方的用户端代码中的一层。对fp的访问由线程环境中的锁控制(不能让线程同时修改同一结构)。

在内核内部,我希望在文件描述符(和/或"打开文件描述")上有一个锁,以防止它同时从两个线程使用。

您可以查找read()的POSIX规范getchar_unlocked()以了解更多关于锁定等的信息——至少对于符合POSIX的实现是这样。

请注意,POSIX仍然使用C99。因此,它没有意识到C11线程设施。C11标准没有read()等(使用文件描述符的文件I/O),因此它没有说明此类系统调用。它也没有提供getchar_unlocked()或其任何亲属。

注意:我已经有一段时间没有接触内核了,但这是它过去的工作方式。

对于磁盘文件:
你能在追加模式下打开文件,写块大小为<= BLKSIZE吗?

在POSIX环境中,足够小的块大小可以保证在POSIX中进行原子写入(实际上,限制可能大于BLKSIZE……我懒得四处寻找替代符号)。

将保证追加到文件末尾。。。用于支持查找的设备。结合原子写作,你应该是金子。

每个缓冲区必须独立,假设一些"外国"信息可能会跟随它

对于tty:
附加模式在这里没有意义。和以前一样,但注意行尾变得更加重要。这在很大程度上不适用于阅读。tty被视为控制序列的代码也可能会让你绊倒,即使序列启用的模式也会在块之间分裂。

对于其他设备:
在这里可能会变得棘手。取决于设备。

我假设您指的是通用字符设备(例如tty),因为您不是特定的。据我所知,每个fd类型的操作(例如read()/write())都直接映射到对驱动程序的调用中。

因此,驱动程序将接收每个write()的数据块作为一个整体,并且在完成之前不会看到下一个的数据(例如,数据排队等待传输)。

但是,如果驱动程序没有同时消耗整个数据块(即write()返回的字节数小于指定的字节数,则无法保证线程能够在另一个线程执行不同的write(。

此外,正如Johnathan Leffler所指出的,如果您使用带有进程级缓冲的标准I/O,那么所有的赌注都将落空

最重要的是,如果使用直接fd写入,则每次写入都将直接映射到一个驱动程序函数调用。从那时起,由驱动程序决定写入是否是原子的。

编辑:wlformyd提出了在多个处理器上的多个线程之间锁定的问题。据我所知,FD上没有锁定,事实上,这是无效的,因为多个FD可以用来访问同一个设备。

我认为这取决于驱动程序本身进行锁定,以防止对内部队列和/或硬件的争用。从这个意义上说,在多处理器系统上,内核不会阻止对驱动程序的写入例程的多次同时访问。但是,一个编写正确的驱动程序应该进行锁定,以防止两个写调用之间的输出混合。

最新更新