【问题标题】:In what order does user space code execute?用户空间代码以什么顺序执行?
【发布时间】:2012-04-10 15:34:59
【问题描述】:

您好,我正在编写一个读取和写入特定设备的字符驱动程序。由于我是菜鸟,这是一个非常简单易用的字符驱动器,它只使用最简单的协议,例如打开、读取、写入和释放。为了测试我的驱动程序,我使用了以下程序……下面是我的用户空间程序的源代码。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <signal.h>
#include <poll.h>

int main(void){
int num;
char *buff;
FILE *fd = fopen("/dev/hi","a+");
num = fprintf(fd,"this is sentence 1 !!");
num = fprintf(fd,"this is sentence 2 !!");
num = fprintf(fd,"this is sentence 3 !!");
num = fprintf(fd,"this is sentence 4 !!");
num = fprintf(fd,"this is sentence 5 !!");
buff = malloc(sizeof(char) * num+1);
fread(buff,sizeof(char),num+1,fd);
printf("%s\n",buff);
fread(buff,sizeof(char),num+1,fd);
printf("%s\n",buff);
fread(buff,sizeof(char),num+1,fd);
printf("%s\n",buff);
fread(buff,sizeof(char),num+1,fd);
printf("%s\n",buff);
fread(buff,sizeof(char),num+1,fd);
printf("%s\n",buff);
free(buff);
close(fd);
return 0;
}

现在,我的驱动程序如何工作并不重要,重要的是我调用读写方法的顺序。理想情况下,如果按照我编写代码的顺序写入驱动程序并按照我编写代码的顺序读取驱动程序,那就太好了。但是我注意到,如果我编写了类似 ...

的代码
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <signal.h>
#include <poll.h>

int main(void){
int num;
char *buff;
FILE *fd = fopen("/dev/hi","w");
num = fprintf(fd,"this is sentence 1 !!");
num = fprintf(fd,"this is sentence 2 !!");
num = fprintf(fd,"this is sentence 3 !!");
num = fprintf(fd,"this is sentence 4 !!");
num = fprintf(fd,"this is sentence 5 !!");
    close(fd);
    fd = fopen("/dev/hi","r");
buff = malloc(sizeof(char) * num+1);
fread(buff,sizeof(char),num+1,fd);
printf("%s\n",buff);
fread(buff,sizeof(char),num+1,fd);
printf("%s\n",buff);
fread(buff,sizeof(char),num+1,fd);
printf("%s\n",buff);
fread(buff,sizeof(char),num+1,fd);
printf("%s\n",buff);
fread(buff,sizeof(char),num+1,fd);
printf("%s\n",buff);
free(buff);
close(fd);
return 0;
}

我注意到 fprintf() 仅在我关闭文件描述符时写入,最糟糕的是,在我从设备读取后执行。当然,我想写入我的设备,然后从中读取,但这并不是按顺序发生的。这给我的印象是用户空间中的许多事情同时执行,这让我感到困惑。在处理用户空间时,我如何知道我的设备函数被调用的顺序。抱歉,如果这似乎含糊不清,我会详细说明任何模糊不清的地方。

感谢任何回复!

【问题讨论】:

  • 我会使用系统调用write,而不是标准库中的fprintffputs。或者至少经常打电话给fflush
  • 感谢您的帮助!

标签: c linux-kernel kernel driver smp


【解决方案1】:

您对“fd”的写入正在被缓存,并且仅在您关闭设备驱动程序后才写入设备驱动程序。 这是正常的,这样做是为了减少系统调用的次数。

如果您确实需要将每次写入发送到设备,请尝试在每次写入后添加对 fsync() 的调用。 或者,由于它是一个字符驱动程序,它很可能是行缓冲的,请尝试在每行的末尾添加一个 '\n'。

【讨论】:

  • fsync 不会这样做,因为他使用 FILE*(并称它们为 fds ;-),但 fflush 应该这样做。
  • 我认为添加换行符也会阻止缓冲。
【解决方案2】:

用户空间中的代码按顺序执行(除非您使用并行性或其他一些混淆顺序的概念显式工作)。

我怀疑,您解释为“模糊”的内容来自 fprintf 的缓冲。

您可以通过在每个 fprintf 之后调用 fflush(fd) 来刷新缓冲区。并且您可以在事先致电setbuf(fd, NULL) 时将其完全禁用。

【讨论】:

    【解决方案3】:

    查看fflushfsync 以清除缓冲输出,并在读取之前提交写入。

    【讨论】:

    • 请注意 fflush 将 FILE* 作为参数,而不是文件描述符。他会想要 fsync。
    • @KristofProvost:没有 fflush 是正确的,混淆来自于原始发布者使用 FILE* 并将其称为 fd 的事实。
    • 哦,对了。我真的应该比期望一个名为 fd 的变量包含一个文件描述符更好。
    【解决方案4】:

    正如其他人所说,这是关于缓冲,而不是一些奇怪的执行顺序效果。使用 fflush 刷新流并实际写入数据,或使用较低级别的 openwrite 等调用。

    但我认为应该指出另一件事:

    您似乎对流和文件描述符有些困惑。您将 FILE* 称为“fd”,然后说它是文件描述符。但是 FILE* 是流,而不是文件描述符。文件描述符是底层的东西,被stdio库隐藏了。

    Linux提供文件描述符,你可以通过调用open得到,然后你可以用write写到那个文件描述符,用close关闭它。 stdio 库添加了另一个级别,有自己的调用(fopenfwritefprintffclose 等),以及它自己的缓冲,位于文件描述符之上。

    另外请注意,您应该使用 fclose 来关闭流,而不是 close

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-10-10
      • 2019-07-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-26
      • 2018-10-02
      相关资源
      最近更新 更多