达内Unix编程.doc
- 【下载声明】
1. 本站全部试题类文档,若标题没写含答案,则无答案;标题注明含答案的文档,主观题也可能无答案。请谨慎下单,一旦售出,不予退换。
2. 本站全部PPT文档均不含视频和音频,PPT中出现的音频或视频标识(或文字)仅表示流程,实际无音频或视频文件。请谨慎下单,一旦售出,不予退换。
3. 本页资料《达内Unix编程.doc》由用户(无敌的果实)主动上传,其收益全归该用户。163文库仅提供信息存储空间,仅对该用户上传内容的表现方式做保护处理,对上传内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知163文库(点击联系客服),我们立即给予删除!
4. 请根据预览情况,自愿下载本文。本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
5. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007及以上版本和PDF阅读器,压缩文件请下载最新的WinRAR软件解压。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Unix 编程
- 资源描述:
-
1、Unix环境编译讲稿Version 1.0Unix Kernel Programming达内IT培训集团加拿大达内集团研发二部 修订历史摘要日期修改原因版本文档创建2009-4-18新建1.0目录1.Unix系统函数53.1.内存管理53.1.1.内存管理在语言结构上的变化53.1.2.Unix/Linux内存管理53.1.3. 物理内存和虚拟内存53.1.4. C 风格的内存分配程序63.1.5.Unix/Linux的基本内存分配程序63.2.Linux标准IO93.3.目录管理293.4.系统信息353.5.时间与日期381.Unix系统函数3.1.内存管理3.1.1.内存管理在语言结构上
2、的变化C/C+语言的内存管理如下阶段变化 1. 从malloc/free到new/delete.这场变革是OOP技术兴起的产物。C+是强类型语言,new/delete的主要成果也就是加强了类型观念,减少了强制类型转换的需求。但是从内存管理角度看,这个变革并没有多少的突破性。 2. 从new/delete到内存配置器(allocator)。自从STL被纳入C+标准库后,C+世界产生了巨大的变化。而从内存管理角度来看,allocator的引入也是C+内存管理一个突破。留意一下你就可以发现,整个STL所有组件的内存均从allocator分配。也就是说,STL并不推荐使用new/delete进行内存管
3、理,而是推荐使用allocator.3.1.2.Unix/Linux内存管理Unix/Linux低层采用三层结构,实际使用中可以方便映射到两层或者三层结构,以适用不同的硬件结构。最下层的申请内存函数get_free_page。之上有三种类型的内存分配函数1.kmalloc类型。内核进程使用,基于切片(slab)技术,用于管理小于内存页的内存申请。思想出发点和应用层面的内存缓冲池同出一辙。但它针对内核结构,特别处理,应用场景固定,不考虑释放。2.vmalloc类型。内核进程使用。用于申请不连续内存。3.brk/mmap类型。用户进程使用。malloc/free实现的基础。3.1.3. 物理内存和
4、虚拟内存要理解内存在程序中是如何分配的,首先需要理解如何将内存从操作系统分配给程序。计算机上的每一个进程都认为自己可以访问所有的物理内存。显然,由于同时在运行多个程序,所以每个进程不可能拥有全部内存。实际上,这些进程使用的是虚拟内存。只是作为一个例子,让我们假定您的程序正在访问地址为 629 的内存。不过,虚拟内存系统不需要将其存储在位置为 629 的 RAM 中。实际上,它甚至可以不在 RAM 中 如果物理 RAM 已经满了,它甚至可能已经被转移到硬盘上!由于这类地址不必反映内存所在的物理位置,所以它们被称为虚拟内存。操作系统维持着一个虚拟地址到物理地址的转换的表,以便计算机硬件可以正确地响
5、应地址请求。并且,如果地址在硬盘上而不是在 RAM 中,那么操作系统将暂时停止您的进程,将其他内存转存到硬盘中,从硬盘上加载被请求的内存,然后再重新启动您的进程。这样,每个进程都获得了自己可以使用的地址空间,可以访问比您物理上安装的内存更多的内存。在 32-位 x86 系统上,每一个进程可以访问 4 GB 内存。现在,大部分人的系统上并没有 4 GB 内存,即使您将 swap 也算上, 每个进程所使用的内存也肯定少于 4 GB。因此,当加载一个进程时,它会得到一个取决于某个称为 系统中断点(system break)的特定地址的初始内存分配。该地址之后是未被映射的内存 用于在 RAM 或者硬盘
6、中没有分配相应物理位置的内存。因此,如果一个进程运行超出了它初始分配的内存,那么它必须请求操作系统“映射进来(map in)”更多的内存。(当内存的虚拟地址有一个对应的物理地址来存储内存内容时,该内存将被映射。)3.1.4. C 风格的内存分配程序C 编程语言提供了两个主要的函数: 1. malloc:该函数分配给定的字节数,并返回一个指向它们的指针。如果没有足够的可用内存,那么它返回一个空指针。 2.free:该函数获得指向由 malloc 分配的内存片段的指针,并将其释放,以便以后的程序或操作系统使用。其他还有两个函数:calloc与realloc函数,依赖上面两个函数。函数说明:#inc
7、lude void *calloc(size_t nmemb, size_t size);void *malloc(size_t size);void free(void *ptr);void *realloc(void *ptr, size_t size);示例代码:略3.1.5.Unix/Linux的基本内存分配程序基于 UNIX 的系统有两个可映射到附加内存中的基本系统调用: 1.brk: brk() 是一个非常简单的系统调用。得到一个系统中断点,该位置是进程映射的内存边界。 brk() 只是简单地将这个位置向前或者向后移动,就可以向进程添加内存或者从进程取走内存。 2.mmap: mm
8、ap(),或者说是“内存映像”,类似于 brk(),但是更为灵活。首先,它可以映射任何位置的内存,而不单单只局限于进程。其次,它不仅可以将虚拟地址映射到物理的 RAM 或者 swap,它还可以将它们映射到文件和文件位置,这样,读写内存将对文件中的数据进行读写。不过,在这里,我们只关心 mmap 向进程添加被映射的内存的能力。 munmap() 所做的事情与 mmap() 相反。brk() 或者 mmap() 都可以用来向我们的进程添加额外的虚拟内存。brk函数说明:#include int brk(void *end_data_segment); void *sbrk(intptr_t inc
9、rement);int brk(void *eds); brk动态地改变数据段所用的内存数量,这种改变是通过重置程序的截断值来完成的,所谓的截断值是数据段结尾以上的第一个位置的地址。分配的内存空间水截断值增加而增加,如果成功,数据段结尾是eds,返回0,否则返回-1,全局变量error 置为ENOMEM void *sbrk(int amount); 在以分配的数据段中增加或减少amount字节数内存,代码示例:利用brk函数,实现与malloc相同的功能:#include #include void* myalloc(int bytes)void * addr_start=sbrk(0);
10、printf(%xn,addr_start);int re=brk(addr_start+bytes);printf(%xn,sbrk(0);return addr_start;int main()void* p=myalloc(20);int* pi=(int*)p;int i=0;for(i=i;i=5;i+)*pi=i;pi+;printf(%xn,pi);sleep(200);return 0;Mmap函数说明:#include void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offse
11、t); int munmap(void *start, size_t length);参数start:指向欲映射的内存起始地址,通常设为 NULL,代表让系统自动选定地址,映射成功后返回该地址。参数length:代表将文件中多大的部分映射到内存。参数prot:映射区域的保护方式。可以为以下几种方式的组合:1.PROT_EXEC 映射区域可被执行2.PROT_READ 映射区域可被读取3.PROT_WRITE 映射区域可被写入4.PROT_NONE 映射区域不能存取参数flags:影响映射区域的各种特性。在调用mmap()时必须要指定MAP_SHARED 或MAP_PRIVATE。1.MAP_F
12、IXED 如果参数start所指的地址无法成功建立映射时,则放弃映射,不对地址做修正。通常不鼓励用此旗标。2.MAP_SHARED对映射区域的写入数据会复制回文件内,而且允许其他映射该文件的进程共享。3.MAP_PRIVATE 对映射区域的写入操作会产生一个映射文件的复制,即私人的“写入时复制”(copy on write)对此区域作的任何修改都不会写回原来的文件内容。4.MAP_ANONYMOUS建立匿名映射。此时会忽略参数fd,不涉及文件,而且映射区域无法和其他进程共享。5.MAP_DENYWRITE只允许对映射区域的写入操作,其他对文件直接写入的操作将会被拒绝。6.MAP_LOCKED
13、将映射区域锁定住,这表示该区域不会被置换(swap)。参数fd:要映射到内存中的文件描述符。如果使用匿名内存映射时,即flags中设置了MAP_ANONYMOUS,fd设为-1。有些系统不支持匿名内存映射,则可以使用fopen打开/dev/zero文件,然后对该文件进行映射,可以同样达到匿名内存映射的效果。参数offset:文件映射的偏移量,通常设置为0,代表从文件最前方开始对应,offset必须是分页大小的整数倍。返回值:若映射成功则返回映射区的内存起始地址,否则返回MAP_FAILED(1),错误原因存于errno 中。错误代码:1.EBADF 参数fd 不是有效的文件描述词2.EACCE
14、S 存取权限有误。如果是MAP_PRIVATE 情况下文件必须可读,使用MAP_SHARED则要有PROT_WRITE以及该文件要能写入。3.EINVAL 参数start、length 或offset有一个不合法。4.EAGAIN 文件被锁住,或是有太多内存被锁住。5.ENOMEM 内存不足。代码示例:#include #include #include #include #include #include #include #include #include int main()/*内存映射*/*分配4字节匿名内存空间*/int * p=mmap(0,4,PROT_READ|PROT_WRI
15、TE,MAP_PRIVATE|MAP_ANONYMOUS,0,0);/*请改变上面的保护设置试试程序的限制*/if(errno)printf(%sn,strerror(errno);*p=20;printf(%dn,*p);/*int *q;*q=30;*/return 0;3.2.Linux标准IO3.2.1.IO基本方法open,write,read函数说明:openSYNOPSIS #include #include #include int open(const char *pathname, int flags); int open(const char *pathname, int
16、 flags, mode_t mode); int creat(const char *pathname, mode_t mode);open 函数用于打开和创建文件。对于 open 函数来说,第三个参数(.)仅当创建新文件时才使用,用于指定文件的访问权限位(access permission bits)。pathname 是待打开/创建文件的路径名(如 C:/cpp/a.cpp);oflag 用于指定文件的打开/创建模式,这个参数可由以下常量(定义于 fcntl.h)通过逻辑或构成。 1.O_RDONLY 只读模式 2.O_WRONLY 只写模式 3.O_RDWR 读写模式打开/创建文件时,
17、至少得使用上述三个常量中的一个。以下常量是选用的: 1.O_APPEND 每次写操作都写入文件的末尾 2.O_CREAT 如果指定文件不存在,则创建这个文件 3.O_EXCL 如果要创建的文件已存在,则返回 -1,并且修改 errno 的值 4.O_TRUNC 如果文件存在,并且以只写/读写方式打开,则清空文件全部内容 5.O_NOCTTY 如果路径名指向终端设备,不要把这个设备用作控制终端。 6.O_NONBLOCK 如果路径名指向 FIFO/块文件/字符文件,则把文件的打开和后继 I/O设置为非阻塞模式(nonblocking mode)以下三个常量同样是选用的,它们用于同步输入输出 1.
18、O_DSYNC 等待物理 I/O 结束后再 write。在不影响读取新写入的数据的 前提下,不等待文件属性更新。 2.O_RSYNC read 等待所有写入同一区域的写操作完成后再进行 3.O_SYNC 等待物理 I/O 结束后再 write,包括更新文件属性的 I/Oopen 返回的文件描述符一定是最小的未被使用的描述符。函数说明:write#include ssize_t write(int filedes, const void *buf, size_t nbytes); 返回值:写入文件的字节数(成功);-1(出错)write 函数向 filedes 中写入 nbytes 字节数据,数
19、据来源为 buf 。返回值一般总是等于 nbytes,否则就是出错了。常见的出错原因是磁盘空间满了或者超过了文件大小限制。函数说明:read#include ssize_t read(int filedes, void *buf, size_t nbytes); 返回值:读取到的字节数;0(读到 EOF);-1(出错) read 函数从 filedes 指定的已打开文件中读取 nbytes 字节到 buf 中。以下几种情况会导致读取到的字节数小于 nbytes : A. 读取普通文件时,读到文件末尾还不够 nbytes 字节。例如:如果文件只有 30 字节,而我们想读取 100 字节,那么实际
展开阅读全文