- Linux程序设计(第4版)
- (英)Neil Matthew Richard Stones
- 1629字
- 2021-04-09 20:04:46
3.11 高级主题:fcntl和mmap
本节我们将讨论的主题你可能会想跳过,因为它们很少会被用到。话虽如此,但我们还是把它放在这里供你参考,因为在解决一些棘手问题时,它们可以提供比较简单的解决方案。
3.11.1 fcntl系统调用
fcntl系统调用对底层文件描述符提供了更多的操纵方法。
利用fcntl系统调用,你可以对打开的文件描述符执行各种操作,包括对它们进行复制、获取和设置文件描述符标志、获取和设置文件状态标志,以及管理建议性文件锁等。
对不同操作的选择是通过选取命令参数cmd不同的值来实现的,其取值定义在头文件fcntl.h中。根据所选择命令的不同,系统调用可能还需要第三个参数arg。
❑ fcntl(fildes, F_DUPFD, newfd):这个调用返回一个新的文件描述符,其数值等于或大于整数newfd。新文件描述符是描述符fildes的一个副本。根据已打开文件数目和newfd值的情况,它的效果可能和系统调用dup(fildes)完全一样。
❑ fcntl(fildes, F_GETFD):这个调用返回在fcntl.h头文件里定义的文件描述符标志,其中包括FD_CLOEXEC,它的作用是决定是否在成功调用了某个exec系列的系统调用之后关闭该文件描述符。
❑ fcntl(fildes, F_SETFD, flags):这个调用用于设置文件描述符标志,通常仅用来设置FD_CLOEXEC。
❑ fcntl(fildes, F_GETFL)和fcntl(fildes, F_SETFL, flags):这两个调用分别用来获取和设置文件状态标志和访问模式。你可以利用在fcntl.h头文件中定义的掩码O_ ACCMODE来提取出文件的访问模式。其他标志包括那些当open调用使用O_CREAT打开文件时作为第三参数出现的标志。注意,你不能设置所有的标志,特别是不能通过fcntl设置文件的权限。
你还可以通过fcntl实现建议性文件锁。详细信息请参考fcntl手册页的第二节,或者阅读本书的第7章,我们将在那里讨论文件锁。
3.11.2 mmap函数
UNIX提供了一个有用的功能以允许程序共享内存,Linux内核从2.0版本开始已经把这一功能包括进来。mmap(内存映射)函数的作用是建立一段可以被两个或更多个程序读写的内存。一个程序对它所做出的修改可以被其他程序看见。
这一功能还可以用在文件的处理上。你可以使某个磁盘文件的全部内容看起来就像是内存中的一个数组。如果文件由记录组成,而这些记录又能够用C语言中的结构来描述的话,你就可以通过访问结构数组来更新文件的内容了。
这要通过使用带特殊权限集的虚拟内存段来实现。对这类虚拟内存段的读写会使操作系统去读写磁盘文件中与之对应的部分。
mmap函数创建一个指向一段内存区域的指针,该内存区域与可以通过一个打开的文件描述符访问的文件的内容相关联。
你可以通过传递off参数来改变经共享内存段访问的文件中数据的起始偏移值。打开的文件描述符由fildes参数给出。可以访问的数据量(即内存段的长度)由len参数设置。
你可以通过addr参数来请求使用某个特定的内存地址。如果它的取值是零,结果指针就将自动分配。这是推荐的做法,否则会降低程序的可移植性,因为不同系统上的可用地址范围是不一样的。
prot参数用于设置内存段的访问权限。它是下列常数值的按位OR结果。
❑ PROT_READ:允许读该内存段。
❑ PROT_WRITE:允许写该内存段。
❑ PROT_EXEC:允许执行该内存段。
❑ PROT_NONE:该内存段不能被访问。
flags参数控制程序对该内存段的改变所造成的影响,可以使用的选项如表3-7所示。
表3-7
msync函数的作用是:把在该内存段的某个部分或整段中的修改写回到被映射的文件中(或者从被映射文件里读出)。
内存段需要修改的部分由作为参数传递过来的起始地址addr和长度len确定。flags参数控制着执行修改的具体方式,可以使用的选项如表3-8所示。
表3-8
munmap函数的作用是释放内存段:
下面的程序mmap.c演示了如何利用mmap和数组方式的存取操作来修改一个结构化数据文件。注意,2.0版本之前的Linux内核不完全支持mmap的这种用法。这个程序在Sun Solaris和其他操作系统上也能够正确运行。
实验 使用mmap函数
(1)我们先定义一个RECORD数据结构,然后创建出NRECORDS个记录,每个记录中保存着它们各自的编号。然后把这些记录都追加到文件records.dat里去。
(2)接着,我们把第43条记录中的整数值由43修改为143,并把它写入第43条记录中的字符串。
(3)现在把这些记录映射到内存中,然后访问第43条记录,把它的整数值修改为243(同时更新该记录中的字符串),使用的还是内存映射的方法。
在第13章中,你将学习另外一种共享内存机制:System V共享内存。