zl程序教程

您现在的位置是:首页 >  系统

当前栏目

Linux文件系统的桌面应用

Linux应用 桌面 文件系统
2023-06-13 09:13:46 时间
本文中要介绍一个所谓的"Linux文件系统的守护神",这是指一个能实时地观察Linux文件系统的变化情况的程序模块。能够实时的观察文件系统的变化情况,并做出及时的适当的反应,这对于应用Linux做桌面计算机系统来说,是十分的有趣,也是十分的重要的。本文还要介绍Linux文件系统的异步I/O的扩展。同样,这对于Linux系统的桌面应用也是关键的。 1、Linux文件系统的守护神 传统的Linux文件系统呈现给用户程序的界面,确实是十分的干净利落。用户程序可以打开一个文件,向文件中线性的写入数据,从文件的某一位置开始,线性的读出数据,关闭一个文件,删除一个文件,创建一个文件,等等。请看,只有这么若干个简洁的操作原语,可是却能提供这么多丰富的应用。但是,我们注意到,用于访问Linux的文件系统的这些操作原语,并没有提供非常复杂的加锁解锁的功能。这是一件很奇妙的事情,如果来自不同的用户程序的请求发生了冲突怎么办呢? 我们不妨走的再靠近一点,仔细的看看删除一个文件是怎样进行的。如果已经有一个用户程序在访问一个文件,而另外一个用户程序正好要删除这一个文件,这时会发生些什么呢?我们知道,Linux的文件系统是基于所谓的inode的,每个文件都相伴有一个inode。在inode中记录了关于这个文件的一些系统信息,比如文件的所有者,文件相关的一些权限记录,关于文件的若干个时间戳,等等。在内存中的inode还维持着一个关于自己的使用计数。每当一个inode所代表的文件被打开一次,这个inode就把关于自己的使用计数加一。每当这个inode所代表的文件一被关闭,这个inode就把关于自己的使用计数减一。当用户程序删除一个文件的时候,相关的系统调用很快就返回到这个用户程序,告诉它,相应的文件已经被删除了。但是相应的inode还是保留在系统中,inode首先要检查自己的使用计数,如果使用计数为零,那么LinuxKernel才可以真正的去删除这个文件。如果使用计数大于零,也就是说,还有其它的用户程序在访问这一个文件,那么LinuxKernel需要等待这些其他的用户程序一个个都完成对这一个文件的访问才行。也就是说,要等到这个inode的使用计数掉到零,才能真正的去删除这一个文件。 我们可以设想一下,如果有一个MP3播放程序在播放一首MP3音乐,我们觉得它不好听,就到硬盘上找到这个文件,把它rm掉了。这时候,MP3播放程序并不受到影响,还是可以继续播放这首MP3音乐,虽然这时候在文件系统上用ls已经找不到这个MP3音乐文件了。实际上,一直要到MP3播放程序停止播放这首MP3音乐,然后Linux文件系统才真正的从硬盘上删除这个MP3文件。这个经验和我们在Windows平台上遇到的截然不同。 在Windows平台上,当我们试图在文件夹窗口中用鼠标点击右键菜单删除Winamp正在播放的一首MP3音乐的时候,Windows系统会用一个弹出对话框告诉我们,这个文件正在被使用,没办法删除。Windows系统的关于删除文件的这样一个解释,如果使用不当的话,会带来一个滑稽可笑的问题。我们可以设想一下,用户的一个P2P的文件共享程序提供了一个MP3文件以供别人下载,恰巧这个MP3音乐文件十分的热门,不断的有人来下载,这个用户最终决定要节省一下带宽,想要把这个MP3音乐文件删除掉,但是Windows系统却不允许用户这样做,因为这个P2P的文件共享程序总是在使用这个MP3文件。用户要想删除这个文件,不得不先把P2P的文件共享程序给停下来!呵呵。 但是Linux的文件系统的操作原语也有它自己的问题。我们知道,在一个LinuxShell的命令行上,先rm,然后再ls,非常的干净,被rm的文件没有了,被删除了。但是我们可以设想有一个图形界面的文件管理程序,当用户从Shell的命令行上rm掉一个文件的时候,这个图形界面的文件管理程序并没有收到任何人发给它的任何消息,它还以为什么都没有发生,被删除掉的文件还在那儿。这实在是很U.G.L.Y.啊。 那么要想解决这个问题,一个明显的但是非常不好的办法,就是让一个后台进程Daemon每隔一个很短的时间间隔,就检查一下文件系统上这个目录的情况,看看有没有发生什么变化。这个办法的缺点真的是显而易见的,不但系统的性能受到影响,而且它的反应也还不是实时的。 如果我们需要用户程序能够实时地了解文件系统上某一个目录的变化情况,从实时这个角度出发,显然,我们需要有一个中断机制。我们都知道,硬件中断能够实时地把系统某一个部件的情况反映给中央处理器,同样的,要想把位于系统内核中的文件系统的情况实时地反映给用户程序,我们也需要一个由操作系统内核到达用户进程的软件中断机制。熟悉Linux系统编程的读者朋友们立即就会想到,这个中断机制在Linux系统中早已就有了,这就是信号传递signal。 找到了信号传递这样一个中断用户进程的机制,一切似乎都已齐备,看来可以动手实现这样一个Linux文件系统的守护神,来实时地监视文件系统的变化情况,并且及时地把消息通知给用户程序了。不过且慢,让我们搜索一下LinuxKernel,看看是否有别人也在做同样的工作。哈哈,果不其然,原来这样一个实时地监视文件系统情况的机制早已在Linux内核中实现了。下面一段就是取自LinuxKernel文档的一段小小例程,说明了LinuxKernel中的dnotify功能的用法。dnotify就是指directorynotification,监视文件系统上一个目录中的情况。 #define_GNU_SOURCE    /*neededtogetthedefines*/
#include<fcntl.h>     /*inglibc2.2thishastheneeded
valuesdefined*/
#include<signal.h>
#include<stdio.h>
#include<unistd.h>

staticvolatileintevent_fd; //信号处理例程    
staticvoidhandler(intsig,siginfo_t*si,void*data)
{
event_fd=si->si_fd;
}

intmain(void)
{
structsigactionact;
intfd;

//登记信号处理例程
act.sa_sigaction=handler;
sigemptyset(&act.sa_mask);
act.sa_flags=SA_SIGINFO;
sigaction(SIGRTMIN,&act,NULL);

//需要了解当前目录"."的情况
fd=open(".",O_RDONLY);
fcntl(fd,F_SETSIG,SIGRTMIN);
fcntl(fd,F_NOTIFY,DN_MODIFY|DN_CREATE|DN_MULTISHOT);
/*wewillnowbenotifiedifanyofthefiles
in"."ismodifiedornewfilesarecreated*/
while(1){
//收到信号后,就会执行信号处理例程。
//而pause()也就结束了。
pause();
printf("Goteventonfd=%d\n",event_fd);
}
} 上面这一小段例程,对于熟悉Linux系统编程的读者朋友们来说,是很容易理解的。程序首先注册一个信号处理例程,然后通知Kernel,我要观察fd上的DN_MODIFY和DN_CREATE和DN_MULTISHOT事件。(关于这些事件的详细定义,请读者朋友们参阅文后所列的参考资料。)LinuxKernel收到这个请求后,把相应的fd的inode给做上记号,然后LinuxKernel和用户应用程序就自顾自去处理各自的别的事情去了。等到inode上发生了相应的事件,LinuxKernel就把信号发给用户进程,于是开始执行信号处理例程,用户程序对文件系统上的变化也就可以及时的做出反应了。而在这整个过程中,系统以及用户程序的正常运行基本上未受到性能上的影响。这里还需要说明的是,dnotify并没有通过增加新的系统调用来完成它的功能,而是通过fcntl来完成任务的。增加一个系统调用,相对来说是一个很大的手术,而且如果设计不当,处理得不好的话,伤疤会一直留在那里,这是LinuxKernel的开发者们所非常不愿意见到的事情。 2、Linux文件系统的异步I/O扩展 对于桌面计算机系统来说,能够快速的响应用户的请求,这也是十分关键的。换句话说,当用户移动鼠标的时候,不管系统正在进行什么天大的、重要的、神圣的、不可打断的工作,它都得立即停下,并且要让鼠标立即流畅的在计算机屏幕上完美地运动起来。对于习惯在传统的Linux命令行上工作的读者朋友们来说,让鼠标能够在任何时间都可以在计算机屏幕上向无头苍蝇一样地乱窜,竟然被当成是最重要的系统任务,这实在有一点让人难以接受。不过,当你从Linux命令行上转移到GNOME或者KDE这样的图形界面的用户环境的时候,鼠标被锁死,百分之百的也是会让你失去理智的。所以,还是让我们接受这一个现实,看一看如何才能增加系统的响应速度吧。 从文件系统的角度讲,特别是考虑到网络文件系统,它的响应速度有可能会相当的慢。当用户在文件管理程序中,选择了对文件进行某一个操作以后,文件系统可能会需要相当长的时间,才能完成这一操作。如果文件管理程序必须要等待文件系统完成这一操作,然后才能继续的话,这显然会给文件管理程序的用户带来非常不愉快的经历。解决这一个问题的办法,就是要实现异步的文件系统I/O。 在Linux的Gnome桌面环境中,由GnomeVFS包裹了真正的Linux文件系统I/O,实现了一个异步的文件系统I/O接口API。我们可以看到下面这个用GnomeVFS打开文件的例子。

enum_GnomeVFSOpenMode{
GNOME_VFS_OPEN_NONE=0,
GNOME_VFS_OPEN_READ=1<<0,
GNOME_VFS_OPEN_WRITE=1<<1,
GNOME_VFS_OPEN_RANDOM=1<<2
}; typedefenum_GnomeVFSOpenModeGnomeVFSOpenMode; typedefvoid(*GnomeVFSAsyncOpenCallback)
(GnomeVFSAsyncHandle*handle,
GnomeVFSResultresult,
gpointercallback_data); GnomeVFSResultgnome_vfs_async_open
(GnomeVFSAsyncHandle**handle_return,
constgchar*text_uri,
GnomeVFSOpenModeopen_mode,
GnomeVFSAsyncOpenCallbackcallback,
gpointercallback_data);    我们注意到,上面的代码段中,用户程序为了打开一个文件,向GnomeVFS注册了一个callback例程。在注册了这一个callback例程之后,函数调用就立即返回给用户程序,用户程序就可以处理自己的别的事情去了,比如进一步响应来自用户的其??肭螅?鹊取6?蔽募?低惩瓿啥晕募?拇蚩?僮饕院螅?nomeVFS就会调用刚刚注册的callback例程,通知用户程序,文件已经打开。 3、小结 我们在本文中了解了LinuxKernel中的dnotify,可以帮助我们实时地监视文件系统目录树中的变化情况;也了解了Gnome桌面环境的GnomeVFS异步文件系统I/O扩展;可以帮助用户程序不至于被文件系统的请求所Block。这两个功能对于Linux系统在桌面上的应用都是很重要的。