Chinaunix首页 | 论坛 | 博客
  • 博客访问: 19733672
  • 博文数量: 679
  • 博客积分: 10495
  • 博客等级: 上将
  • 技术积分: 9308
  • 用 户 组: 普通用户
  • 注册时间: 2006-07-18 10:51
文章分类

全部博文(679)

文章存档

2012年(5)

2011年(38)

2010年(86)

2009年(145)

2008年(170)

2007年(165)

2006年(89)

分类: LINUX

2008-11-20 11:08:26

§3.11 高级主题:fcntl mmap

本节我们将讨论的主题你可能会想暂时跳过,因为它们很少会被用到。这里介绍的内容可以作为读者的参考,在解决一些棘手问题时,它们可以提供比较简单的解决方案。

     3.11.1 fcntl 系统调用

fcntl系统调用对底层文件描述符提供了更多的控制方法。

#include

int fcntl(int fildes, int cmd);

int fcntl(int fildes, int cmd, long arg);

利用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(内存映射,memory map)函数的作用是建立一段内存,使它能够被两个或更多个程序读写。一个程序对它所做出的修改可以被其他程序看见。

这一功能还可以用在文件的处理上。你可以使某个磁盘文件的全部内容看起来就像是内存中的一个数组。如果文件由记录组成,而这些记录又能够用C语言中的结构来描述的话,你就可以通过访问结构数组对文件的内容进行修改。

这要通过使用带特殊权限集的虚拟内存段才能实现。对这类虚拟内存段的读写会使操作系统去读

写磁盘文件中与之对应的部分。

mmap函数创建一个指向一段内存区域的指针,该指针将与文件的内容相关联,而文件则是通过一个打开的文件描述符来访问。

#include

void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off);

你可以通过传递off参数来改变经共享内存段访问的文件中数据的起始偏移值。打开的文件描述符由fildes参数给出。可以访问的数据量(即内存段的长度)由len参数设置。

你可以通过addr参数请求使用某个特定的内存地址。如果它的取值是零,结果指针将将自动分配。这是推荐的做法,否则会降低程序的可移植性,因为不同系统上的可用地址范围是不一样的。

prot参数用来设置内存段的访问权限。它是下列常数值的按位OR结果:

􀂉 PORT_READ:允许读该内存段。

􀂉 PORT_WRITE:允许写该内存段。

􀂉 PORT_EXEC:允许执行该内存段。

􀂉 PORT_NONE:该内存段不能被访问。

flags参数控制程序对该内存段的改变所造成的影响,如表3-7所示。

3-7

MAP_PRIVATE 内存段是私用的,对它的修改只在此局部范围内有效

MAP_SHARED 把对该内存段的修改保存到磁盘文件中

MAP_FIXED 该内存段必须位于addr指定的地址处

msync函数的作用是把在该内存段的某个部分或整段中的修改写回到被映射的文件中(或者从被映射文件里读出)。

#include

int msync(void *addr, size_t len, int flags);

内存段需要修改的部分由作为参数传递过来的起始地址addr和长度len确定。flags参数控制着执行修改的具体方式,如表3-8所示。

3-8

MS_ASYNC 采用异步写方式

MS_SYNC 采用同步写方式

MS_INVALIDATE 从文件中读回数据

munmap函数的作用是释放内存段:

#include

int munmap(void *addr, size_t len);

下面的程序mmap_eg.c演示了如何利用mmap和数组方式的存取操作对结构化数据文件进行修改。注意,2.0版本之前的Linux内核不完全支持mmap的这种用法。这个程序在Sun Solaris和其他操作系统上也能够正确运行。

实验:使用mmap函数(暂略)

 

 

§3.12 小结

在本章里,我们学习了Linux所提供的直接访问文件和设备的方法。我们介绍了在这些底层函数的基础上建立的库函数是如何为程序设计问题提供灵活的解决方案的。作为学习的成果,我们已经能够只用很少几行代码就编写出功能相当强大的目录扫描例程。

我们还对文件和目录处理进行了细致的学习,在此基础之上,我们已可以把在第2章最后编写的CD唱片应用程序转换为一个C语言程序,使用更具结构化、基于文件的解决方案。但在此阶段,我们还无法给这个程序增加新的功能,所以对整个程序的重写工作将推迟到我们学习了如何处理屏幕显示和键盘输入之后再进行,而这些内容正是接下来的两章的主题。

阅读(4369) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~