【问题标题】:How can you flush a write using a file descriptor?如何使用文件描述符刷新写入?
【发布时间】:2010-09-20 12:51:58
【问题描述】:

事实证明,对 open() 与 fopen() 的整个误解源于 ARM 上的 Linux 2.6.14 内核中存在错误的 I2C 驱动程序。向后移植一个工作位 bashed 驱动程序解决了我试图在这里解决的问题的根本原因。

我正在尝试找出 Linux (I2C) 中的串行设备驱动程序存在的问题。看来,通过在设备上的写入和读取之间添加定时操作系统暂停(睡眠),事情会工作......(好多了)。

除此之外:I2C 的本质是主机读取或写入的每个字节都由线路另一端(从机)上的设备确认 - 改善事物的暂停鼓励我将驱动程序视为异步工作 - 我无法与总线的工作方式相协调。随便...

我想刷新写入以确保(而不是使用固定持续时间的暂停),以某种方式测试写/读事务以多线程友好的方式完成

使用fflush(fd); 的问题在于它需要“fd”作为流指针(不是文件描述符),即

FILE * fd = fopen("filename","r+");
... // do read and writes
fflush(fd);

我的问题是我需要使用ioctl(),它不使用流指针。即

int fd = open("filename",O_RDWR);
ioctl(fd,...);

建议?

【问题讨论】:

  • 在用户级代码中,write() 函数是自动不缓冲的。你不需要冲洗它——它是自动冲洗的。事实上,除非你使用特殊的系统调用,否则它也是与设备驱动程序同步的。
  • 如果您正在编写内核级模块,规则可能会有所不同,但您可能应该使用文件描述符 i/o 而不是标准(文件指针)i/o。

标签: c linux stdio i2c


【解决方案1】:

我认为您正在寻找的可能是

int fsync(int fd);

int fdatasync(int fd);

fsync 会将文件从内核缓冲区刷新到磁盘。 fdatasync 也可以,除了元数据。

【讨论】:

  • OP 声明这是一个 i2c 字符设备,而不是磁盘。
  • 好的,i2c 开发节点没有页面缓冲,因此不需要刷新/同步。设备驱动程序中的 fops 决定了实际做了什么。
  • 虽然这不是 OP 问题的解决方案,但对于其他提出主要标题问题的人来说很有用。我正在通过 fd 写入磁盘,因此了解如何刷新内核缓冲区非常有帮助。
【解决方案2】:

你有两个选择:

  1. 使用fileno()获取与stdio流指针关联的文件描述符

  2. 根本不要使用<stdio.h>,这样您也不必担心刷新 - 所有写入都会立即转到设备,而对于字符设备,write() 调用不会甚至返回到较低级别的 IO 完成(理论上)。

对于设备级 IO,我会说使用 stdio 是很不寻常的。我强烈建议改用较低级别的open()read()write() 函数(根据您以后的回复):

int fd = open("/dev/i2c", O_RDWR);
ioctl(fd, IOCTL_COMMAND, args);
write(fd, buf, length);

【讨论】:

  • 避免 是我一直在做的;我原来帖子中的“旁白”让我想到文件描述符可能已被缓冲。感谢您确认它们不是,我应该寻找另一个原因,因为它会导致 I2C 总线出现问题。
  • 让我们明确一下术语——UNIX 文件描述符是一个整数索引,应该是无缓冲的,以便立即调用写入/读取。对于“大型”写入,它应该非常有效,而对于单字节写入则效率低下。 fopen 为您提供缓冲 I/O。使用打开/读/写。
【解决方案3】:

fflush() 仅刷新 stdio fopen() 层添加的缓冲,由FILE * 对象管理。如内核所见,底层文件本身并未在此级别缓冲。这意味着绕过FILE * 层、使用fileno() 和原始write() 的写入也不会以fflush() 刷新的方式进行缓冲。

正如其他人指出的那样,请尝试不要将两者混合。如果你需要使用ioctl()之类的“原始”I/O函数,那么直接自己open()文件,不用使用fopen<()和stdio的朋友。

【讨论】:

    【解决方案4】:

    您是否尝试过禁用缓冲?

    setvbuf(fd, NULL, _IONBF, 0);
    

    【讨论】:

    • 这对我有用。我不确定我的设置是什么,但我使用了这个和“fsync”(使用 fileno 来获取 int 而不是 FILE*),我能够在关闭并重新打开文件后查找和读取文件。跨度>
    • 这仅适用于 fopen() 而不适用于 open()。最初的问题是关于禁用 open() 调用的缓冲。
    • open() 没有缓冲区,它直接进入设备驱动程序。
    【解决方案5】:

    听起来您正在寻找的是 fsync() 函数(或 fdatasync()?),或者您可以在 open() 调用中使用 O_SYNC 标志。

    【讨论】:

      【解决方案6】:

      如果你想反过来(将 FILE* 与现有文件描述符相关联),请使用 fdopen() :

                                                                FDOPEN(P)
      
      NAME
      
             fdopen - associate a stream with a file descriptor
      
      SYNOPSIS
      
             #include <stdio.h>
      
             FILE *fdopen(int fildes, const char *mode);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-04-26
        • 2020-04-20
        • 2019-06-20
        • 1970-01-01
        • 2012-03-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多