当前位置:   article > 正文

linux 系统调用open和close介绍以及作用和调用关系的理解_linux close

linux close

系统调用open和close介绍以及作用和调用关系的理解

open和close的介绍与用法

名字

打开, open - 打开文件

概要
#include <sys/stat.h>
#include <fcntl.h>
int open(const char **path*, int *oflag*, ...);
int openat(int *fd*, const char **path*, int *oflag*, ...);
  • 1
  • 2
  • 3
  • 4
描述

open() 函数应在文件和文件描述符之间建立连接。它应创建一个引用文件的打开文件描述和一个引用该打开的文件描述的文件描述符。其他 I/O 函数使用该文件描述符来引用该文件。path 参数指向命名文件的路径名。

open() 函数应返回指定文件的文件描述符,按文件描述符分配中所述进行分配。打开的文件描述是新的,因此文件描述符不应与系统中的任何其他进程共享它。除非在 oflag 中设置了O_CLOEXEC标志,否则应清除与新文件描述符关联的FD_CLOEXEC文件描述符标志。

用于标记文件中当前位置的文件偏移量应设置为文件的开头。

打开文件描述的文件状态标志和文件访问模式应根据 oflag 的值进行设置。

flag 的值由以下列表中标志的按位包含 OR 构造,定义于 ** 中。应用程序应在 oflag 的值中准确指定以下前五个值(文件访问模式)之一:

  • O_EXEC

    仅打开以执行(非目录文件)。如果将此标志应用于目录,则结果未指定。

  • O_RDONLY

    仅开放供阅读。

  • O_RDWR

    开放阅读和写作。如果将此标志应用于 FIFO,则结果未定义。

  • O_SEARCH

    仅打开目录进行搜索。如果将此标志应用于非目录文件,则结果未指定。

  • O_WRONLY

    仅对写入开放。

可以使用以下任意组合:

  • O_APPEND

    如果设置,则在每次写入之前,应将文件偏移量设置为文件末尾。

  • O_CLOEXEC

    如果设置,则应设置新文件描述符的FD_CLOEXEC标志。

  • O_CREAT

    如果该文件存在,则此标志不起作用,除非在下面O_EXCL中指出。否则,如果未设置O_DIRECTORY,则应将该文件创建为常规文件;文件的用户 ID 应设置为进程的有效用户 ID;文件的组 ID 应设置为文件父目录的组 ID 或进程的有效组 ID;并且文件模式的访问权限位(请参阅**)应设置为 oflag 参数之后的参数值,该参数的类型mode_t修改如下:对文件模式位和进程文件模式创建掩码补码中的相应位执行按位 AND。因此,文件模式中在文件模式创建掩码中设置了相应位的所有位都将被清除。如果设置了文件权限位以外的位,则效果未指定。oflag 参数后面的参数不会影响文件是打开以进行读取、写入还是同时打开两者。实现应提供一种将文件的组 ID 初始化为父目录的组 ID 的方法。实现可以(但不一定)提供一种实现定义的方式,将文件的组 ID 初始化为调用进程的有效组 ID。

  • O_DIRECTORY

    如果路径解析为非目录文件,则失败并将错误设置为 [ENOTDIR]。

  • O_DSYNC

    [[SIO](javascript:open_code(‘SIO’))] [选项开始] 对文件描述符的写入 I/O 操作应按照同步 I/O 数据完整性完成的定义完成。[选项结束]

  • O_EXCL

    如果设置了O_CREAT和O_EXCL,则如果文件存在,open() 将失败。检查文件是否存在以及文件是否存在的创建应是原子的,相对于执行 open() 在同一目录中命名相同文件名的其他线程,并设置O_EXCL和O_CREAT。如果设置了O_EXCL和O_CREAT,并且路径名为符号链接,则 open() 将失败并将 errno 设置为 [EEXIST],而不管符号链接的内容如何。如果设置了O_EXCL,但未设置O_CREAT,则结果未定义。

  • O_NOCTTY

    如果设置和路径标识终端设备,open()不应导致终端设备成为过程的控制终端。如果路径无法识别终端设备,则应忽略O_NOCTTY。

  • O_NOFOLLOW

    如果路径命名符号链接,则失败并将错误设置为 [ELOOP]。

  • O_NONBLOCK

    打开装有O_RDONLY或O_WRONLY设置的先进先出时:如果设置了O_NONBLOCK,则用于只读的 open() 应立即返回。如果当前没有进程打开文件进行读取,则仅用于写入的 open() 将返回错误。如果O_NONBLOCK很清楚,则用于只读的 open() 应阻塞调用线程,直到线程打开文件进行写入。仅用于写入的 open() 应阻塞调用线程,直到线程打开文件进行读取。打开支持非阻塞的块特殊或字符特殊文件时,将打开:如果设置了O_NONBLOCK,open() 函数将返回而不会阻塞设备准备就绪或可用。设备的后续行为是特定于设备的。如果O_NONBLOCK很清楚,open() 函数应阻塞调用线程,直到设备准备就绪或可用,然后再返回。否则,O_NONBLOCK标志不应导致错误,但未指定文件状态标志是否包含O_NONBLOCK标志。

  • O_RSYNC

    [[SIO](javascript:open_code(‘SIO’))] [选项开始] 对文件描述符的读取 I/O 操作应以O_DSYNC和O_SYNC标志指定的相同完整性级别完成。如果O_DSYNC和O_RSYNC都设置在 oflag 中,则文件描述符上的所有 I/O 操作都应按照同步 I/O 数据完整性完成的定义完成。如果在标志中同时设置了O_SYNC和O_RSYNC,则文件描述符上的所有 I/O 操作都应按照同步 I/O 文件完整性完成的定义完成。[选项结束]

  • O_SYNC

    [[XSI|SIO](javascript:open_code(‘XSI’))] [选项开始] 对文件描述符的写入 I/O 操作应按照同步 I/O 文件完整性完成的定义完成。[选项结束][[XSI](javascript:open_code(‘XSI’))] [选项开始] 常规文件应支持O_SYNC标志,即使不支持“同步输入和输出”选项。[选项结束]

  • O_TRUNC

    如果文件存在并且是常规文件,并且文件O_RDWR或O_WRONLY成功打开,则其长度应截断为0,并且模式和所有者应保持不变。它对FIFO特殊文件或终端设备文件没有影响。它对其他文件类型的影响是实现定义的。使用O_TRUNC而不O_RDWR或O_WRONLY的结果未定义。

  • O_TTY_INIT

    如果 path 标识了伪终端以外的终端设备,则该设备在任何进程中尚未打开,并且O_TTY_INIT设置为 oflag 或O_TTY_INIT值为零,open() 应将任何非标准 termios 结构终端参数设置为提供符合行为的状态;请参阅可以设置的 XBD 参数。如果设备已在任何进程中打开,则未指定O_TTY_INIT是否具有任何影响。如果 path 标识在任何进程中尚未打开的伪终端的从属端,则 open() 应将任何非标准 termios 结构终端参数设置为提供一致性行为的状态,无论是否设置了O_TTY_INIT。如果路径无法识别终端设备,则应忽略O_TTY_INIT。

如果设置了O_CREAT和O_DIRECTORY,并且请求的访问模式既不O_WRONLY也不O_RDWR,则结果未指定。

如果设置了O_CREAT,但文件以前不存在,则在成功完成后,open() 应将文件的上次数据访问、上次数据修改和上次文件状态更改时间戳以及父目录的上次数据修改和上次文件状态更改时间戳标记为更新。

如果设置了O_TRUNC并且文件以前确实存在,则在成功完成后,open() 应将文件的上次数据修改和上次文件状态更改时间戳标记为更新。

返回值

成功完成后,这些函数应打开文件并返回表示文件描述符的非负整数。否则,这些函数应返回 -1 并设置 errno 以指示错误。如果返回 -1,则不得创建或修改任何文件。

错误

如果出现以下情况,这些功能将失败:

在路径前缀的组件上拒绝搜索权限,或者文件存在并且 oflag 指定的权限被拒绝,或者文件不存在并且拒绝要创建的文件的父目录的写入权限,或者指定O_TRUNC并拒绝写入权限。

设置O_CREAT和O_EXCL,并且存在命名文件。

打开()期间捕获了一个信号。

实现不支持此文件的同步 I/O。

路径参数命名一个流文件,并且打开*()期间发生挂起或错误。

命名文件是一个目录,oflag 包含O_WRONLY或O_RDWR,或者包含O_CREAT,但不包含O_DIRECTORY。

在解析路径参数期间遇到的符号链接中存在循环,或者指定了O_NOFOLLOW并且 path 参数命名符号链接。

当前,进程可用的所有文件描述符都处于打开状态。

路径名的组件的长度比 {NAME_MAX} 长。

系统中当前打开的最大允许文件数。

O_CREAT未设置,并且 path 的组件未命名现有文件,或者设置了O_CREAT,并且 path 的路径前缀的组件未命名现有文件,或者 path 指向空字符串。

设置O_CREAT,并且 path 参数至少包含一个非<斜杠>字符,并以一个或多个尾随<斜杠> 字符结尾。如果没有尾随<斜杠>字符的路径将命名现有文件,则不会发生 [ENOENT] 错误。

路径参数命名一个基于流的文件,系统无法分配流。

包含新文件的目录或文件系统无法扩展,该文件不存在,并且指定了O_CREAT。

路径前缀的组件命名既不是目录也不是指向目录的符号链接的现有文件;或者O_CREAT和O_EXCL未指定,则 path 参数至少包含一个非<斜杠>字符,并以一个或多个尾随 字符结尾,并且最后一个路径名组件命名既不是目录也不是指向目录的符号链接的现有文件;或O_DIRECTORY,并且 path 参数解析为非目录文件。

设置O_NONBLOCK,则命名文件为 FIFO,O_WRONLY设置,并且没有进程打开文件以供读取。

命名文件是字符特殊或块特殊文件,与此特殊文件关联的设备不存在。

命名文件是常规文件,文件大小不能在 off_t 类型的对象中正确表示。

命名文件驻留在只读文件系统上,O_WRONLY、O_RDWR、O_CREAT(如果文件不存在)或在 oflag 参数中设置O_TRUNC。

如果出现以下情况,则 openat() 函数将失败:

fd 关联的打开文件描述的访问模式未O_SEARCH并且基础 fd 目录的权限不允许目录搜索。

path 参数不指定绝对路径,并且 fd 参数既不是AT_FDCWD也不是打开以供读取或搜索的有效文件描述符。

path 参数不是绝对路径,fd 是与非目录文件关联的文件描述符。

如果出现以下情况,这些功能可能会失败:

path 参数命名已锁定的伪终端设备的从属端。

参数的值无效。

在解析路径参数期间,遇到了多个 {SYMLOOP_MAX} 符号链接。

路径名的长度超过 {PATH_MAX},或者符号链接的路径名解析产生长度超过 {PATH_MAX} 的中间结果。

路径参数命名流文件,系统无法分配资源。

path 参数命名套接字。

该文件是正在执行的纯过程(共享文本)文件,并且 oflag O_WRONLY或O_RDWR。


以下各节提供了丰富的信息。

例子
打开文件以供所有者写入

下面的示例通过创建文件 /tmp/file(如果该文件尚不存在)或将其长度截断为 0(如果存在)来打开该文件 /tmp/file。在前一种情况下,如果调用创建新文件,则文件的文件模式下的访问权限位将设置为允许所有者读取和写入,并且仅允许组成员和其他人读取。

如果对 open() 的调用成功,则打开文件进行写入。

#include <fcntl.h>
...
int fd;
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
char *pathname = "/tmp/file";
...
fd = open(pathname, O_WRONLY | O_CREAT | O_TRUNC, mode);
...
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
使用存在性检查打开文件

下面的示例使用 open() 函数尝试创建 LOCKFILE 文件并打开它进行写入。由于 open() 函数指定O_EXCL标志,因此如果文件已存在,则调用将失败。在这种情况下,程序假定其他人正在更新密码文件并退出。

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>

#define LOCKFILE "/etc/ptmp"
...
int pfd; /* Integer for file descriptor returned by open() call. */
...
if ((pfd = open(LOCKFILE, O_WRONLY | O_CREAT | O_EXCL,
    S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1)
{
    fprintf(stderr, "Cannot open /etc/ptmp. Try again later.\n");
    exit(1);
}
...
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
打开文件进行写入

下面的示例打开一个文件进行写入,如果该文件尚不存在,则创建该文件。如果该文件确实存在,系统会将该文件截断为零字节。

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>

#define LOCKFILE "/etc/ptmp"
...
int pfd;
char pathname[PATH_MAX+1];
...
if ((pfd = open(pathname, O_WRONLY | O_CREAT | O_TRUNC,
    S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1)
{
    perror("Cannot open output file\n"); exit(1);
}
...
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
名字

close 关闭 - 关闭文件描述符

概要
#include <unistd.h>int close(int *fildes*);
  • 1
描述

close() 函数应解除分配由 fildes 指示的文件描述符。解除分配意味着使文件描述符可供后续调用 open() 或分配文件描述符的其他函数返回。进程在与文件描述符关联的文件上拥有的所有未完成的记录锁都将被删除(即,已解锁)。

如果 close() 被要捕获的信号中断,它将返回 -1,并将 errno 设置为 [EINTR],并且错误的状态未定close() 期间读取或写入文件系统时发生 I/O 错误,则可能会返回 -1,并将 errno 设置为 [EIO];如果返回此错误,则未指定字段的状态。

当与管道或FIFO特殊文件关联的所有文件描述符都关闭时,管道或FIFO中剩余的任何数据都应被丢弃

当与打开的文件描述关联的所有文件描述符都已关闭时,应释放打开的文件描述。

如果文件的链接计数为 0,则当与该文件关联的所有文件描述符都关闭时,应释放文件占用的空间,并且该文件将不再可访问。

[[OB XSR](javascript:open_code(‘OB XSR’))] [选项开始] 如果基于流的配置文件已关闭,并且调用进程之前已注册为接收与该流关联的事件的 SIGPOLL 信号,则对于与该流关联的事件,应取消注册调用进程。流的最后一个关闭()应导致与菲尔德相关的流被拆除。如果未设置O_NONBLOCK,并且没有为 STREAM 发布信号,并且模块的写入队列上有数据,则 close() 应等待未指定的时间(对于每个模块和驱动程序),以便在拆卸 STREAM 之前释放任何输出。可以通过I_SETCLTIME ioctl() 请求来更改时间延迟。如果设置了O_NONBLOCK标志,或者有任何待处理的信号,close() 不应等待输出耗尽,并应立即拆卸 STREAM。

如果实现支持基于 STREAMS 的管道,并且 fildes 与管道的一端相关联,则最后的 close() 将导致管道的另一端发生挂起。此外,如果管道的另一端已被 fattach() 命名,则最后的关闭 () 应强制指定的末端被 fdetach() 分离。如果命名的端点没有与之关联的打开文件描述符并且被分离,则与该端点关联的STREAM也应被拆除。[选项结束]

[[XSI](javascript:open_code(‘XSI’))] [选项开始] 如果菲尔德是指伪终端的主端,并且这是最后一次关闭,则应向控制过程发送SIGHUP信号(如果有的话),其伪终端的从端是控制终端。未指定关闭伪终端的主端是否会刷新所有排队的输入和输出。[选项结束]

[[OB XSR](javascript:open_code(‘OB XSR’))] [选项开始] 如果 fildes 指的是基于流的伪终端的从属端,则可能会向主端发送零长度消息。[选项结束]

当调用 close() 时,如果存在针对 fild 的未完成的可取消异步 I/O 操作,则该 I/O 操作可能会被取消。未取消的 I/O 操作将完成,就好像 close() 操作尚未发生一样。所有未取消的操作应完成,就好像 close() 被阻止一样,直到操作完成。close() 操作本身不需要阻塞等待此类 I/O 完成。是否取消任何 I/O 操作,以及哪个 I/O 操作可以在 close() 时取消,都是实现定义的。

如果内存映射文件 [[SHM](javascript:open_code(‘SHM’))] [选项开始] 或共享内存对象[选项结束]在上次关闭时仍被引用(即,进程已映射它),则内存对象的全部内容将持续存在,直到内存对象变为未引用。如果这是内存映射文件 [[SHM](javascript:open_code(‘SHM’))] [选项开始] 或共享内存对象[选项结束]的最后一次关闭,并且关闭导致内存对象变得未引用,并且内存对象已取消链接,则应删除内存对象。

如果菲尔德斯指的是一个套接字,close() 将导致该套接字被破坏。如果套接字处于连接模式,并且为具有非零延迟时间的套接字设置了SO_LINGER选项,并且套接字具有未传输的数据,则 close() 应阻塞至当前延迟间隔,直到传输所有数据。

返回值

成功完成后,应返回0;否则,应返回 -1 并设置 errno 以指示错误。

错误

如果出现以下情况,则 close() 函数将失败:

fildes 参数不是打开的文件描述符。

close() 函数被信号中断。

如果出现以下情况,close() 函数可能会失败:

读取或写入文件系统时发生 I/O 错误。

以下各节提供了丰富的信息。

例子
重新分配文件描述符

下面的示例关闭与当前进程的标准输出关联的文件描述符,将标准输出重新分配给新的文件描述符,并关闭原始文件描述符以进行清理。此示例假定文件描述符 0(这是标准输入的描述符)未关闭。

#include <unistd.h>
...
int pfd;
...
close(1);
dup(pfd);
close(pfd);
...
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

顺便说一句,这正是可以使用以下方法实现的:

dup2(pfd, 1);
close(pfd);
  • 1
  • 2
关闭文件描述符

在下面的示例中,close() 用于在尝试将文件描述符与流关联失败后关闭该文件描述符。

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

#define LOCKFILE "/etc/ptmp"
...
int pfd;
FILE *fpfd;
...
if ((fpfd = fdopen (pfd, "w")) == NULL) {
    close(pfd);
    unlink(LOCKFILE);
    exit(1);
}
...
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

参考链接

open (opengroup.org)

close (opengroup.org)

问题:如果使用open(fd);即打开了一个文件,但是没有使用close(fd);会出现什么问题?

在stack overflow社区中有下面的介绍

如果我不关闭 C 中的文件,会有什么问题?

假设我们有一个c程序,如下所示:

int fun(char *path) {
    FILE *f = fopen(path, "r");
    int result;
    // Do something here without closing the file
    return result;
}

int main(int argc, char *argv[])
{
    int i = fun(argv[1]);
    printf("%d\n", i);
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

我知道不关闭文件不是一个好习惯。但我想知道什么时候文件将作系统关闭。何时退货或何时退货?当程序被杀死时呢?

回答:根据标准(C11 §5.1.2.2.3 1),“从初始调用函数返回相当于调用退出函数…”,这关闭了所有打开的流。

所以说在文件关闭时,或者主函数返回时,会自动调用退出函数。

文件是受操作系统限制的资源

操作系统限制任何单个进程可以具有的打开文件数。这个数字通常以千为单位。操作系统设置此限制是因为如果一个进程尝试打开数千个文件描述符,则该进程可能存在问题。即使成千上万的文件看起来很多,但仍然有可能遇到限制。

1、Linux系统下,所有进程允许打开的最大fd数量。查询语句
cat /proc/sys/fs/file-max
  • 1
2、Linux系统下,所有进程已经打开的fd数量及允许的最大数量。查询语句:
cat /proc/sys/fs/file-nr
  • 1
3、单个进程允许打开的最大fd数量.查询语句:
ulimit -n
  • 1
4、单个进程(例如进程id为5454)已经打开的fd.查询语句:
ls -l /proc/5454/fd/
  • 1

除了遇到限制的风险外,保持文件打开状态还会使您容易丢失数据。通常,Python和操作系统会努力保护您免受数据丢失。但是,如果您的程序(或计算机)崩溃,则通常的例程可能不会发生,并且打开的文件可能会损坏。

简而言之,让上下文管理管理器管理您的文件是一种防御性技术,易于练习,并且可以使您的代码更好 - 因此您也可以这样做。这就像系好安全带一样。您可能不需要它,但是没有它的成本可能很高。

由于文件是由操作系统管理的有限资源,因此确保文件在使用后关闭将防止难以调试的问题,例如文件句柄用完或遇到数据损坏。最好的防御措施始终是使用上下文管理器打开文件。

open打开文件时,会将文件加载到内存空间

查看进程的status文件:

 cat /proc/1598/status 
  • 1

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FcTA67NT-1665477034674)(image-20221011154303554.png)]

VmRSS对应的值就是物理内存占用

动态查看内存

top -p 1598
  • 1

查看内存信息

cat /proc/1115/statm 
  • 1

423 77 68 1 0 76 0

输出解释

第一列 size:任务虚拟地址空间大小
第二列 Resident:正在使用的物理内存大小
第三列 Shared:共享页数
第四列 Trs:程序所拥有的可执行虚拟内存大小
第五列 Lrs:被映像倒任务的虚拟内存空间的库的大小
第六列 Drs:程序数据段和用户态的栈的大小
第七列 dt:脏页数量

查看运行程序的调用关系

cat /proc/1598/maps
  • 1
00010000-00011000 r-xp 00000000 08:01 502        /media/sda1/app
00020000-00021000 rw-p 00000000 08:01 502        /media/sda1/app
004f0000-00512000 rw-p 00000000 00:00 0          [heap]
76dee000-76f13000 r-xp 00000000 b3:02 349538     /lib/libc-2.23.so
76f13000-76f22000 ---p 00125000 b3:02 349538     /lib/libc-2.23.so
76f22000-76f24000 r--p 00124000 b3:02 349538     /lib/libc-2.23.so
76f24000-76f25000 rw-p 00126000 b3:02 349538     /lib/libc-2.23.so
76f25000-76f28000 rw-p 00000000 00:00 0 
76f28000-76f48000 r-xp 00000000 b3:02 349684     /lib/ld-2.23.so
76f48000-76f49000 rw-p 00000000 00:00 0 
76f56000-76f57000 rw-p 00000000 00:00 0 
76f57000-76f58000 r--p 0001f000 b3:02 349684     /lib/ld-2.23.so
76f58000-76f59000 rw-p 00020000 b3:02 349684     /lib/ld-2.23.so
7ee30000-7ee51000 rw-p 00000000 00:00 0          [stack]
7efd8000-7efd9000 r-xp 00000000 00:00 0          [sigpage]
7efd9000-7efda000 r--p 00000000 00:00 0          [vvar]
7efda000-7efdb000 r-xp 00000000 00:00 0          [vdso]
ffff0000-ffff1000 r-xp 00000000 00:00 0          [vectors]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

总结来说:

使用open(fd)后,不使用close(fd)关闭的话有下面几点危害:

  1. 可能其他线程会操作到本次未关闭的文件描述符,会产生数据泄露。
  2. 在程序中如果会多次使用open(fd)打开设备时,不使用close(fd)关闭设备,会造成资源浪费,并且达到1024上限的时候,会报错,too many fd

单进程程序,不使用close(fd)也是可以的,并不会影响内存和资源的占用,在运行结束时,或者接收到信号退出时,系统自动释放资源,(即自动运行close(fd))

下面是简单的例子:

驱动中有如下函数:

 /*
* @description : 关闭/释放设备
* @param – filp : 要关闭的设备文件(文件描述符)
* @return : 0 成功;其他 失败
*/
static int chrdev_release(struct inode *inode, struct file *filp)
{
	printk("?????????????????????????????\r\n");
	return 0;
}

/*
 * 设备操作函数结构体
*/
 
struct file_operations chrdev_ops = {
	.owner = THIS_MODULE,
	.open = chrdev_open,
	.read = chrdev_read,
	.write = chrdev_write,
	.release = chrdev_release,
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

app中

	retvalue = close(fd);
	if(retvalue < 0){
	printf("Can't close file %s\r\n", filename);
	return -1;
	}

	return 0;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

app1中

/*	retvalue = close(fd);
	if(retvalue < 0){
	printf("Can't close file %s\r\n", filename);
	return -1;
	}
*/
	return 0;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
./app
  • 1
[  843.926272] chrdev_open
[  843.928787] kernel senddata ok!
[  843.932034] 0
[  843.935081] chrdevbase read!
read data:0
[  843.939133] ?????????????????????????????
open succeed
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
./app1
  • 1
[  851.116120] chrdev_open
[  851.118633] kernel senddata ok!
[  851.121881] 0
[  851.123645] chrdevbase read!
read data:0
[  851.128453] ?????????????????????????????
open succeed
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

验证了上述总结中的观点

使用close函数,会执行相应的函数来解决文件描述符等问题,具体的函数不需要了解。其对应的驱动中chrdev_release函数,只是额外运行的程序,和用户空间无关

以下为一部分参考链接:

文件打开的过程——调用fd=open()时操作系统所做的工作 - 走看看 (zoukankan.com)

Linux环境编程——打开文件、open 介绍、open 源码、文件描述符 fd 与文件管理结构 file - 知乎 (zhihu.com)

在linux下,怎么去查看一个运行中的程序, 到底是占用了多少内存 - 走看看 (zoukankan.com)

linux函数深入探索——open函数打开文件是否将文件内容加载到内存空间 (bbsmax.com)

https://zhuanlan.zhihu.com/p/485411986

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/278458
推荐阅读
相关标签
  

闽ICP备14008679号