嵌入式课程设计报告嵌入式文件锁应用.doc
信息技术学院嵌入式操作系统课程综合设计报告书姓 名: XX 班 级: B0905 学 号: XXXX 题 目: 嵌入式文件锁应用 时 间: 2012年6月 指导教师: XXX 摘 要随着PC时代的到来,嵌入式系统技术已经成为了一个万众瞩目的焦点。目前已广泛应用于信息家电、数据网络、工业控制、医疗卫生、航空航天等众多领域。巨大的市场潜力,无穷的商机,吸引了各路英豪纷蹱踏来。为了解决多个进程并发访问同一个文件时所面临的同步问题,Linux采用了文件加锁技术。介绍了Linux中各类文件锁的概念,详细分析了与文件锁密切相关的系统调用,并给出了一个文件锁的使用实例。本课程设计是以Red Hat linux为基础平台,利用fcntl函数实现。关键字:Linux 文件锁 文件描述符 同步问题 并发访问 目 录一、任务要求4二、设计方案4三、设计原理41、函数产生背景42、lock( )43 、fcntl( )5四程序流程图6五.VI 简介6六.结果与调试7七.总结8八参考文献:9附录:10一、任务要求 在多任务操作系统环境中, 如果一个进程尝试对正在被其他进程读取的文件进行写操作, 可能会导致正在进行读操作的进程读取到一些被破坏或者不完整的数据; 如果两个进程并发对同一个文件进行写操作,可能会导致该文件遭到破坏。因此, 为了避免发生这种问题, 必须要采用某种机制来解决多个进程并发访问同一个文件时所面临的同步问题, 由此而产生了文件加锁方面的技术。二、设计方案通过编写在多用户共享下给文件上锁的程序,进一步熟悉 Linux 中文件 I/O 相关的应用开发,并且熟练的掌握 fcntl()函数的使用.在文件已经共享的情况下如何操作,也就是当多个用户共同使用,操作一个文件的情况,这时,Linux 通常采用的方法是给文件上锁,来避免共享的资源产生竞争的状态。 文件锁包括建议性锁和强制性锁。建议性锁要求每个上锁文件的进程都要检查是否有锁存在,并且尊重已有的锁。在一般情况下,内核和系统都不使用建议性锁。强制性锁是由内核执行的锁,当一个文件被上锁进行写入操作的时候,内核将阻止其他任何文件对其进行读写操作。采用强制性锁对性能的影响很大,每次读写操作都必须检查是否有锁存在。在 Linux 中,实现文件上锁的函数有 lock 和 fcntl,其中 flock 用于对文件施加建议性锁, fcntl 不仅可以施加建议性锁,还可以施加强制锁。同时, fcntl 还能对文件的某一记录进行上锁,也就是记录锁. 记录锁又可分为读取锁和写入锁,其中读取锁又称为共享锁,它能够使多个进程都能在文件的同一部分建立读取锁。而写入锁又称为排斥锁,在任何时刻只能有一个进程在文件的某个部分上建立写入锁。当然,在文件的同一部分不能同时建立读取锁和写入锁。三、设计原理1、函数产生背景:在某文件已经共享的情况下,当多个用户共享使用与操作这个文件时,为了避免共享的资源产生竞争的状态,linux通常采用的方法是给文件上锁,即文件锁。在linux中为实现文件锁的功能而产生了lock()函数和fcntl()函数。2、lock( ) Linux 2. 6 内核利用系统调用flock( ) 实现了共享模式强制锁, 但flock ( )只能实现对整个文件进行加锁,不能实现记录级的加锁,函数原型如下: int flock( int fd, int operat ion) ;fd 是需要加锁的文件的描述符, operation 可以为下列值:LOCK_SH: 共享锁, 多个进程可以同时拥有对文件的共享锁。LOCK_EX: 互斥锁, 一个文件只能上一把互斥锁。LOCK_UN: 解锁操作。LOCK_NB: 如果进程不能获取指定的锁,函数将不阻塞,缺省时,进程将睡眠等待。这几个控制选项可以进行组合使用或操作。3 、fcntl( )fcntl函数能复制一个现有的描述符、获得/设置文件描述符记录、获得/设置文件状态标志、获得/设置异步I/O所有权以及获得/设置记录锁。在使用fcntl给文件上锁时,可以首先测试该锁是否会被已存在的锁阻止,接下来就使用F_SETFL给文件上锁。在给文件上锁时,关键是给flock结构体赋予相应的变量,再将flock传给fcntl即可。它是非常强大的文件锁,可以实现对纪录进行加锁,函数原型如下:int fcnt l ( int fd, int cmd, struct flock * lock) ;其中, 参数fd 表示文件描述符; 参数cmd 指定要进行的锁操作, 由于fcntl( )函数功能比较多, 这里先介绍与文件锁相关的三个取值F_GETLK、F_SETLK以及F_SETLKW。这三个值均与flock 结构有关。F_lock 结构如下所示:struct flockshortl_type ;shortl_whence;off_tl_start;off_tl_len;pid_tl_pid; ;在该结构中, l type 用于指定锁的类型, 它可以是F_RELCK、F_WRLCK、F_UNLCK ,分别是共享锁(读锁) 、互斥锁和解锁操作。l_whence 指定如何使用l_start 来设置锁定的起始位置, 如果l_whence 取SEEK_SET , 表示从l_start 指定的位置作为锁定的起始位置; 如果l_whence 取SEEK_CUR, 表示锁定从当前文件指针的位置加上l_start 开始; 如果l_whence 取SEEK_END, 表示锁定从当前文件的结束位置加上l_start开始。1_1en 表示锁定区域的长度。1_pid 表示进行锁定的进程的进程号。使用fcntl 进行文件加锁, 通常按照下面的步骤来进行: 首先填充结构中的参数, 然后以匹配的方式打开文件, 最后调用fcntl 进行文件加锁。返回值成功则返回 0,若有错误则返回-1,错误原因存于errno 。开 始四程序流程图 开 始 文件是否成功文件是否已上 锁?失败成功未上锁已上锁给出打开 文件失败 的提示给文件置 写入锁/读 取锁并给 出提示. 如: 进程号提示上锁 成功,并显示上了什么锁和上锁的进程号提示上锁 失败,并显 示已上什 么锁和上 锁的进程 号解 锁结 束结 束图 1.文件记录锁功能流程图 图 2. 文件写入锁/读取锁功能流程图五.VI 简介vi 是 Linux/Unix 世界里极为普遍的可视化的全屏幕文本编辑器(visual edit),几乎可以说任何一台 Linux/Unix 机器都会提供这个软件. vi 有三种状态,即编辑方式,插入方式和命令方式.在命令方式下,所有 命令都要以:开始,所键入的字符系统均作命令来处理,如:q 代表退出,:w 表 示存盘. 当你进入 vi 时, 会首先进入命令方式 (同时也是编辑方式) 按下 i 就 . 进入插入方式,用户输入的可视字符都添加到文件中,显示在屏幕上.按下 ESC 就可以回到命令状态(同时也是编辑方式). 六.结果与调试终端1运行结果:终端2运行结果:七.总结我认为,在这学期的嵌入式课程设计中,在收获知识的同时,还收获了阅历,收获了成熟,在此过程中,我通过查找大量资料,请教老师,以及不懈的努力,不仅培养了独立思考的能力,在各种其它能力上也都有了提高。更重要的是,我学会了很多学习的方法。而这是日后最实用的,真的是受益匪浅。要面对社会的挑战,只有不断的学习、实践,再学习、再实践。不管怎样,这些都是一种锻炼,一种知识的积累,能力的提高。完全可以把这个当作基础东西,只有掌握了这些最基础的,才可以更进一步,取得更好的成绩。很少有人会一步登天吧。永不言弃才是最重要的。而且,这对于我的将来也有很大的帮助。以后,不管有多苦,我想我们都能变苦为乐,找寻有趣的事情,发现其中珍贵的事情。就像中国提倡的艰苦奋斗一样,我都可以在结束之后变的更加成熟,会面对需要面对的事情。嵌入式课程设计虽然结束了,也留下了很多遗憾,因为由于时间的紧缺和许多课业的繁忙,并没有做到最好,但是,最起码我没有放弃,它是我们的骄傲!相信以后我会以更加积极地态度对待我们的学习、对待我们的生活。我们的激情永远不会结束,相反,我们会更加努力,努力的去弥补自己的缺点,发展自己的优点,去充实自己,只有在了解了自己的长短之后,我们会更加珍惜拥有的,更加努力的去完善它,增进它。只有不断的测试自己,挑战自己,才能拥有更多的成功和快乐!to us, happiness equals success! 快乐至上,享受过程,而不是结果!认真对待每一个任务,珍惜每一分一秒,学到最多的知识和方法,锻炼自己的能力,这个是我设计过程中学到的最重要的东西,也是以后都将受益匪浅的! 对本学期嵌入式课程设计的评价趣味性强,不仅锻炼能力,而且可以学到很多东西,在与老师和同学的交流过程中,互动学习,将知识融会贯通。八参考文献:【1】马士兵Linux视频教程 【2】鸟哥的Linux私房菜【3】嵌入式Linux实时操作系统及应用编程【4】美 Dav id A Rusling 著. 朱珂译. Linux 编程白皮书M . 附录:#include<unistd.h>#include<sys/file.h>#include<sys/types.h>#include<sys/stat.h>#include<stdio.h>#include<stdlib.h>#include<string.h>void lock_set(int fd,int type);int lock_reg(int fd,int cmd,int type,off_t offset,int whence,off_t len);int main(int argc,char *argv)int fd,nwrite,nread,len,c;char reply;char buff100;char buf_r100;fd=open("hello",O_RDWR|O_CREAT,0666);if(fd<0)perror("open");exit(1);while(c=getopt(argc,argv,"w:r")!=-1)switch(c)case 'w':lock_set(fd,F_WRLCK);len=sizeof(buff);if(nwrite=write(fd,buff,len)>0)printf("write successn");while(1)printf("want to unlock?(Y/N)n");scanf("%c",&reply);if(reply='Y')|(reply='y')lock_set(fd,F_UNLCK);break;elsesleep(2);continue;break;case 'r':lock_set(fd,F_RDLCK);lseek(fd,0,SEEK_SET);if(nread=read(fd,buf_r,100)>0)printf("read:%sn",buf_r);while(1)printf("want to unlock?(Y/N)n");scanf("%c",&reply);if(reply='Y')|(reply='y')lock_set(fd,F_UNLCK);break;elsesleep(2);continue;break;default:printf("prog+w+content-rn");break;close(fd);exit(0);void lock_set(int fd,int type)struct flock lock;lock.l_whence=SEEK_SET;lock.l_start=0;lock.l_len=0;while(1)lock.l_type=type;if(fcntl(fd,F_SETLK,&lock)=0)if(lock.l_type=F_RDLCK)printf("read lock set by %dn",getpid();else if(lock.l_type=F_WRLCK)printf("write lock set by %dn",getpid();else if(lock.l_type=F_UNLCK)printf("release lock set by %dn",getpid();return;fcntl(fd,F_GETLK,&lock);if(lock.l_type!=F_UNLCK)if(lock.l_type=F_RDLCK)printf("read lock already set by %dn",lock.l_pid);else if(lock.l_type=F_WRLCK)printf("write lock already set by %dn",lock.l_pid);getchar();int lock_reg(int fd,int cmd,int type,off_t offset,int whence,off_t len)struct flock lock;lock.l_type=type;lock.l_whence=whence;lock.l_start=offset;lock.l_len=len;return(fcntl(fd,cmd,&lock);lock_test(int fd,int type,off_t offset,int whence,off_t len)struct flock lock;lock.l_type=type;lock.l_whence=whence;lock.l_start=offset;lock.l_len=len;if(fcntl(fd,F_GETLK,&lock)<0)perror("fcntl");if(lock.l_type=F_UNLCK)return(0);return(lock.l_pid);