1

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

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

感谢您的任何回复!

4

4 回答 4

4

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

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

于 2012-03-27T05:41:34.747 回答
2

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

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

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

于 2012-03-27T05:42:42.907 回答
1

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

于 2012-03-27T05:41:23.810 回答
0

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

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

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

Linux 提供了文件描述符,您可以通过调用open来获得,然后您可以使用write写入该文件描述符,并使用 close 关闭。stdio 库在文件描述符之上添加了另一个级别,具有自己的调用(fopenfwritefprintffclose等)和自己的缓冲。

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

于 2012-03-27T06:04:18.483 回答