Linux内核设计与实现---虚拟文件系统

虚拟文件系统

  • 1 通用文件系统
  • 2 文件系统抽象层
  • 3 Unix文件系统
  • 4 VFS对象及其数据结构
    • 其他VFS对象
  • 5 超级快对象
    • 超级块操作
  • 6 索引节点对象
    • 索引节点操作
  • 7 目录项对象
    • 目录项状态
    • 目录项缓存
    • 目录项操作
  • 8 文件对象
  • 9 和文件系统相关的数据结构
  • 10 和进程相关的数据结构
  • 11 Linux中的文件系统

虚拟文件系统,简称VFS,是内核的子系统,为用户空间程序提供了文件系统相关的接口。系统中所有文件系统不但依赖VFS共存,而且也依靠VFS系统协同工作。通过虚拟文件系统,程序可以 利用标准的UNIX文件系统调用不同介质上不同文件系统进行读写操作。

如下图:使用cp命令从ext3文件系统格式的硬盘拷贝数据到ext2文件系统格式的可移动磁盘上。两种不同的文件系统,两种不同的介质,连接到同一个VFS上。
在这里插入图片描述

1 通用文件系统

VFS使得用戶可以直接使用open()、write()和read()这样的系统调用而无需考虑具体文件系统实际物理介质。系统调用还可以在这些不同的文件系统和介质之间执行。正是由于包括Linux在内的现代操作系统引入了抽象层,通过虚拟接口访问文件系统,才使得这种协作性和通用性成为可能,新的文件系统和新种类的存储介质都能找到进入Linux之路,程序无需重写,甚至无需重新编译。

2 文件系统抽象层

之所以可以使用这种通用接口对所有类型的文件系统进行操作,是因为内核在它的底层文件系统接口上建立了一个抽象层,该抽象层使Linux能够支持各种文件系统,即便是它们在功能和行为上存在很大差别。为了支持多文件系统,VFS提供了一个通用文件系统模型,该模型囊括了我们所能想到的文件系统的常用功能和行为。

VFS抽象层之所以能链接各种各样的文件系统,是因为它定义了所有文件系统都支持的基本的、概念上的接口和数据结构。同时实际文件系统也将自身的诸如如何打开文件、目录是什么等概念在形式上与VFS定义保持一致。因为实际文件系统的代码在同一的接口和数据结构下隐藏了具体的实现细节,所以在VFS层和内核的其他部分看来,所有的文件系统都是相同的。

内核通过抽象层能够方便、简单地支持各种类型的文件系统,实际文件系统通过编程提供VFS所期望的抽象接口和数据结构,这样,内核就可以毫不费力地和任何文件系统系统工作。并且这样提供给用户空间的接口,也可以和任何文件系统无缝连接在一起,完成实际工作。

我们在用户空间调用write方法,会首先在VFS找到一个通用系统调用sys_write()处理,sys_wirte()会找到所在的文件系统给出的写操作,然后通过该写操作,往物理介质上写数据。
在这里插入图片描述

3 Unix文件系统

Unix使用了四种和文件系统相关的传统抽象概念:文件、目录项、索引节点和安装点。

从本质上说文件系统是特殊的数据分层存储结构,它包含文件、目录和相关的控制信息。在Unix中,文件系统被安装在一个特定的安装点上,所有的已安装文件系统都作为根文件系统数的枝叶出现在系统中。

文件其实可以看做是一个有序字节串,字节串中第一个字节是文件的头,最后一个字节时文件的尾。文件通过目录组织起来,文件目录好比一个文件夹,用来容纳相关文件。因为目录也可以包含子目录,所以目录可以层层嵌套,形成文件路径。路径中的每一部分都被称作目录条目。/home/wolfman/butter的根目录是/,目录home、wolfman和文件butter都是目录条目,它们被统称为目录项。在Unix中,目录属于普通文件,它列出包含在其中的所有文件。由于VFS把目录当做文件对待,所以可以对目录和文件执行相同的操作。

Unix系统将文件的相关信息和文件本身这两个概念加以区分,文件的相关信息,有时被称作文件的元数据,被存储在一个单独的数据结构中,该结构被称为索引节点(inode)。

4 VFS对象及其数据结构

VFS其实采用的是面向对象的设计思路,使用一族数据结构来代表通用文件对象。VFS有四个主要的对象类型,它们分别是:

  • 超级块对象,它代表一个已安装的文件系统
  • 索引节点对象,它代表一个文件
  • 目录项对象,它代表一个目录项,是路径的一个组成部分。
  • 文件对象,它代表由进程打开的文件

注意,因为VFS将目录作为一个文件来处理,所以不存在目录对象。目录项代表的是路径中的一个组成部分,它可能包括一个普通文件,目录项不同于目录,但目录却和文件相同。

其他VFS对象

VFS使用了大量结构体对象,它所包括的对象远远多于上面提到的这几种主要对象。比如每个注册的文件系统都是由file_system_type结构体来表示,它描述了文件系统及其能力,另外,每一个安装点也都有vfsmount结构体表示,它包含安装点的相关信息。如位置和安装标志等。
后面还要介绍三个与进程相关的结构体,它们描述了文件系统以及和进程相关的文件,这三个结构体分别是file_struct、fs_struct和namespace。

5 超级快对象

各种文件系统都必须实现超级块,该对象用于存储特定文件系统的信息,通常对应于存放在磁盘特定扇区中的文件系统超级块或文件系统控制块。对于并非基于磁盘的文件系统(如基于内存的文件系统,比如sysfs),它们会在使用现场创建超级块并将其保存到内存中。

超级块对象由spuer_block结构体表示,定义在文件linux/fs.h中。创建、管理和销毁超级块对象的代码位于文件fs/super.c中。超级块对象通过alloc_super()函数创建并初始化,在文件系统安装时,内核回调用该函数以便从磁盘读取文件系统超级块,并且将其信息填充到内存中的超级块对象中。

超级块操作

超级块对象中最重要的一个域是s_op,它指向超级块的操作函数表。超级块操作函数表如下

struct super_operations {struct inode *(*alloc_inode)(struct super_block *sb);void (*destroy_inode)(struct inode *);void (*read_inode) (struct inode *);void (*dirty_inode) (struct inode *);int (*write_inode) (struct inode *, int);void (*put_inode) (struct inode *);void (*drop_inode) (struct inode *);void (*delete_inode) (struct inode *);void (*put_super) (struct super_block *);void (*write_super) (struct super_block *);int (*sync_fs)(struct super_block *sb, int wait);void (*write_super_lockfs) (struct super_block *);void (*unlockfs) (struct super_block *);int (*statfs) (struct super_block *, struct kstatfs *);int (*remount_fs) (struct super_block *, int *, char *);void (*clear_inode) (struct inode *);void (*umount_begin) (struct super_block *);int (*show_options)(struct seq_file *, struct vfsmount *);
};

该结构体中的每一项都是指向超级快操作函数的指针,超级块操作函数执行文件系统和索引节点的低层操作。
上面所有函数都是由VFS在进程上下文中调用,必要时,它们都可以阻塞,这其中的一些函数是可选的:在超级块操作表中,文件系统可以将不需要的函数指针设置成NULL,如果VFS发现操作函数指针是NULL,那它要么就会调用通用函数执行相应操作,要门什么也不做,如何选择取决于函数。

6 索引节点对象

索引节点对象包含了内核在操作文件或目录时需要的全部信息。对于Unix风格的文件系统来说,这些信息可以从磁盘索引节点直接读入。如果一个文件系统没有索引节点,那么,不管这些相关信息在磁盘上是怎么存放的,文件系统都必须从中提取这些消息。

索引节点对象由inode结构体表示,定义在文件linux/fs.h中。

索引节点操作

索引节点对象中的inode_operations项描述了VFS用以操作索引节点对象的所有方法,这些方法由文件系统实现。inode_operatiions结构体定义在文件linux/fs.h中

struct inode_operations {int (*create) (struct inode *,struct dentry *,int, struct nameidata *);struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *);int (*link) (struct dentry *,struct inode *,struct dentry *);int (*unlink) (struct inode *,struct dentry *);int (*symlink) (struct inode *,struct dentry *,const char *);int (*mkdir) (struct inode *,struct dentry *,int);int (*rmdir) (struct inode *,struct dentry *);int (*mknod) (struct inode *,struct dentry *,int,dev_t);int (*rename) (struct inode *, struct dentry *,struct inode *, struct dentry *);int (*readlink) (struct dentry *, char __user *,int);int (*follow_link) (struct dentry *, struct nameidata *);void (*put_link) (struct dentry *, struct nameidata *);void (*truncate) (struct inode *);int (*permission) (struct inode *, int, struct nameidata *);int (*setattr) (struct dentry *, struct iattr *);int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *);int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);ssize_t (*listxattr) (struct dentry *, char *, size_t);int (*removexattr) (struct dentry *, const char *);
};

7 目录项对象

VFS把目录当作文件看待,所以在路径/bin/vi中,bin和vi都是文件,bin是特殊的目录文件,而vi是一个普通文件,路径中的每个组成部分都由一个索引节点对象表示。
为了方便查找操作,VFS引入了目录项的概念。每个目录项代表路径一个特定部分,对前一个例子来说,/、bin和vi都属于目录项对象。前两个是目录,最后一个是普通文件。
目录项也可包括安装点。在路径/mnt/cdrom/foo中,/、mnt、cdrom和foo都属于目录项对象。VFS在执行目录操作时,如果需要的话,会现场创建目录项对象。

目录项对象由dentry结构体表示,定义在文件linux/dcache.h中。

struct dentry {atomic_t d_count;unsigned int d_flags;		/* protected by d_lock */spinlock_t d_lock;		/* per dentry lock */struct inode *d_inode;		/* Where the name belongs to - NULL is* negative *//** The next three fields are touched by __d_lookup.  Place them here* so they all fit in a 16-byte range, with 16-byte alignment.*/struct dentry *d_parent;	/* parent directory */struct qstr d_name;struct list_head d_lru;		/* LRU list */struct list_head d_child;	/* child of parent list */struct list_head d_subdirs;	/* our children */struct list_head d_alias;	/* inode alias list */unsigned long d_time;		/* used by d_revalidate */struct dentry_operations *d_op;struct super_block *d_sb;	/* The root of the dentry tree */void *d_fsdata;			/* fs-specific data */struct rcu_head d_rcu;struct dcookie_struct *d_cookie; /* cookie, if any */struct hlist_node d_hash;	/* lookup hash list */	int d_mounted;unsigned char d_iname[DNAME_INLINE_LEN_MIN];	/* small names */
};

不同于前面两个对象,目录项对象没有对应的磁盘数据结构,VFS根据字符串性式的路径名现场创建它,而且由于目录项对象并非真正保存在磁盘上,所以目录结构体没有是否被修改的标志。

目录项状态

目录项对象有三种有效状态:被使用、未被使用和负状态。
一个被使用的目录项对应一个有效的索引节点(d_inode指向相应的索引节点)并且表明该对象存在一个或多个使用者(d_count为正值)。一个目录项处于被使用状态,意味着它正被VFS使用并且指向有效的索引节点,因此不能被丢弃。

一个未被使用的目录项对应一个有效的索引节点,但是VFS当前并未使用它(d_count为0)。该目录项对象指向一个有效的对象,而且被保留在缓存中以便需要时在使用它。

一个负状态的目录项没有对应的有效索引节点(d_node为NULL),因为索引节点已经被删除了,或路径不再正确了,但是目录项仍然保留,以便快速解析以后的路径查询。

目录项缓存

如果VFS层遍历路径名中所有的元素并将它们逐个解析成目录项对象,这将是一件非常费力的工作,会浪费大量的时间,所以内核将目录项对象缓存在目录项缓存(简称dcache)中。
目录项缓存包括三个主要部分:

  • "被使用的"目录项链表
  • "最近被使用的"双向链表。该链表含有未被使用的和负状态的目录项对象。由于该链表以时间顺序插入,所以链头的结点是最新数据,当内核必须通过删除结点项回收内存时,会从链尾删除结点项,因为尾部的节点最旧,在近期内再次被使用的可能性最小
  • 散列表和相应的散列函数用来快速地将给定路径解析为相关目录项对象。

举个例子,假设你需要在自己目录中编译一个源文件,/home/dracula/src/foo.c,每一次对foo.c文件进行访问,VFS必须沿着嵌套的目录依次解析全部路径:/、home、dracula、src和最终的foo.c。为了避免每次访问该路径名都进行这种耗时的操作,VFS会先在目录项缓存中搜索路径名,如果找到了,直接访问。相反,如果该目录项在目录项缓存中并不存在,VFS就必须通过查文件系统为每个路径分量解析路径,解析完毕后,再将目录项对象加入dcache中,以便以后可以快速访问它。

目录项操作

dentry_operation结构体指明了VFS操作目录项的所有方法。
该结构体定义在文件<linux/dcache.h>中

struct dentry_operations {int (*d_revalidate)(struct dentry *, struct nameidata *);int (*d_hash) (struct dentry *, struct qstr *);int (*d_compare) (struct dentry *, struct qstr *, struct qstr *);int (*d_delete)(struct dentry *);void (*d_release)(struct dentry *);void (*d_iput)(struct dentry *, struct inode *);
};

8 文件对象

文件对象表示进程已打开的文件。文件对象是已打开的文件在内存中的表示,该对象由相应的open()系统调用创建,由close()系统调用销毁。因为多个进程可以同时打开和操作同一个文件,所以同一个文件也可能存在多个对应的文件对象(一个进程打开了一个文件就会有一个文件对象)。文件对象仅仅在进程观点上代表已打开文件,它反过来指向目录项对象(索引节点),其实只有目录项对象才表示已打开的实际文件,虽然一个文件对应的文件对象不是唯一的,但对应的索引节点和目录项对象是唯一的。

文件对象由file结构体表示,定义在文件linux/fs中

struct file {struct list_head	f_list;struct dentry		*f_dentry;struct vfsmount         *f_vfsmnt;struct file_operations	*f_op;atomic_t		f_count;unsigned int 		f_flags;mode_t			f_mode;int			f_error;loff_t			f_pos;struct fown_struct	f_owner;unsigned int		f_uid, f_gid;struct file_ra_state	f_ra;unsigned long		f_version;void			*f_security;/* needed for tty driver, and maybe others */void			*private_data;#ifdef CONFIG_EPOLL/* Used by fs/eventpoll.c to link all the hooks to this file */struct list_head	f_ep_links;spinlock_t		f_ep_lock;
#endif /* #ifdef CONFIG_EPOLL */struct address_space	*f_mapping;
};

类似于目录项对象,文件对象实际上没有对应的磁盘数据,所以在结构体中没有代表其对象是否为脏,是否需要写回磁盘的标志。文件对象通过f_dentry指针指向相关的目录项对象。目录项会指向相关的索引节点,索引节点会记录文件是否是脏的。

文件对象的操作由file_operations结构体表示,定义在linux/fs.h中

struct file_operations {struct module *owner;loff_t (*llseek) (struct file *, loff_t, int);ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);ssize_t (*aio_read) (struct kiocb *, char __user *, size_t, loff_t);ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);ssize_t (*aio_write) (struct kiocb *, const char __user *, size_t, loff_t);int (*readdir) (struct file *, void *, filldir_t);unsigned int (*poll) (struct file *, struct poll_table_struct *);int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);int (*mmap) (struct file *, struct vm_area_struct *);int (*open) (struct inode *, struct file *);int (*flush) (struct file *);int (*release) (struct inode *, struct file *);int (*fsync) (struct file *, struct dentry *, int datasync);int (*aio_fsync) (struct kiocb *, int datasync);int (*fasync) (int, struct file *, int);int (*lock) (struct file *, int, struct file_lock *);ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *);ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);int (*check_flags)(int);int (*dir_notify)(struct file *filp, unsigned long arg);int (*flock) (struct file *, int, struct file_lock *);
};

9 和文件系统相关的数据结构

除了以上几种VFS基础对象外,内核还使用了另外一些标准数据结构来管理文件系统的其他相关数据。第一个结构体是file_system_type,用来描述各种特定文件系统类型,比如ext3。第二个结构体是vfsmount,用来描述一个安装文件系统的实例。

因为Linux支持众多不同的文件系统,所以内核必须由一个特殊的结构体来描述每种文件系统的功能和行为。file_system_type定义在linux/fs.h中

struct file_system_type {const char *name;int fs_flags;struct super_block *(*get_sb) (struct file_system_type *, int,const char *, void *);void (*kill_sb) (struct super_block *);struct module *owner;struct file_system_type * next;struct list_head fs_supers;
};

每种文件系统,不管有多少个实例安装到系统中,还是根本就没有安装到奥系统中,都只有一个file_system_type结构。

当文件系统被实际安装时,将有一个vfsmount结构体在安装时被创建。该结构体用来代表文件系统的实例。
vfsmount结构被定义在linux/mount.h中

struct vfsmount
{struct list_head mnt_hash;struct vfsmount *mnt_parent;	/* fs we are mounted on */struct dentry *mnt_mountpoint;	/* dentry of mountpoint */struct dentry *mnt_root;	/* root of the mounted tree */struct super_block *mnt_sb;	/* pointer to superblock */struct list_head mnt_mounts;	/* list of children, anchored here */struct list_head mnt_child;	/* and going through their mnt_child */atomic_t mnt_count;int mnt_flags;int mnt_expiry_mark;		/* true if marked for expiry */char *mnt_devname;		/* Name of device e.g. /dev/dsk/hda1 */struct list_head mnt_list;struct list_head mnt_fslink;	/* link in fs-specific expiry list */struct namespace *mnt_namespace; /* containing namespace */
};

10 和进程相关的数据结构

系统中的每一个进程都有自己的一组打开的文件,像根文件系统、当前工作目录、安装点等。有三个数据结构将VFS层和系统的进程紧紧联系在一起,它们分别是:files_struct、fs_struct和namespace结构体。

files_struct结构体定义在文件linux/file.h中。该结构体由进程描述符中的files域指向。所有与每个进程相关的信息如打开的文件及文件描述符都包含在其中,其结构体描述如下:

struct files_struct {atomic_t count;spinlock_t file_lock;     /* Protects all the below members.  Nests inside tsk->alloc_lock */int max_fds;int max_fdset;int next_fd;struct file ** fd;      /* current fd array */fd_set *close_on_exec;fd_set *open_fds;fd_set close_on_exec_init;fd_set open_fds_init;struct file * fd_array[NR_OPEN_DEFAULT];
};

fd数组指针指向已打开的文件对象链表,默认情况下,指向fd_array数组,因为NR_OPEN_DEFALUT等于32,所以该数组可以容纳32个文件对象,如果一个进程锁打开的文件对象超过32个,内核将分配一个新数组,并且将fd指针指向它。

fs_struct由进程描述符的fs域指向,它包含文件系统和进程相关的信息,定义在linux/fs_struct.h中。

struct fs_struct {atomic_t count;rwlock_t lock;int umask;struct dentry * root, * pwd, * altroot;struct vfsmount * rootmnt, * pwdmnt, * altrootmnt;
};

该结构包含了当前进程的当前工作目录(pwd)和根目录(root)。

namespace定义在文件linux/namespace.h中,由进程描述符中的namespace域指向。2.4内核以后,单进程命名空间被加入到内核中,它使得每一个进程都在系统中都看到唯一的安装系统文件

struct namespace {atomic_t		count;struct vfsmount *	root;struct list_head	list;struct rw_semaphore	sem;
};

list域是连接已安装文件系统的双向链表,它包含的元素组成了全体命名空间。默认情况下,所有的进程共享同样的命名空间,只有在进行clone()操作时使用CLONE_NEWNS标志,才会给进程一个另外的命名空间结构体的拷贝。

11 Linux中的文件系统

Linux支持相当多种类的文件系统,从本地文件系统。如ext2和ext3,到网络文件系统,如NFS和Coda、VFS层提供了给这些文件系统一个统一的实现框架,而且还提供了能和标准系统调用交换工作的同一接口。由于VFS层的存在,使得Linux实现新文件系统的工作变得简单起来,它可以轻松地使这些文件系统通过Unix系统调用而协同工作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/379627.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java里面的几种路径的区别

1&#xff0c;相对路径 相对路径就是指由这个文件所在的路径引起的跟其它文件&#xff08;或文件夹&#xff09;的路径关系。 也就是说&#xff1a; 对于如图所示&#xff1a;一news.html为例 在WEB15工程下的WebContent下的WEB-INF下的news.html 当我访问的news.html的时候…

Linux内核设计与实现---块I/O层

块I/O层1 解刨一个块设备2 缓冲区和缓冲区头3 bio结构体新老方法对比4 请求队列5 I/O调度程序I/O调度程序的工作Linus电梯最终期限I/O调度程序预测I/O调度程序完全公正的排队I/O调度程序空操作的I/O调度程序I/O调度程序的选择系统中能够 随机访问 固定大小数据片的设备被称为块…

算法---数

数1 最大公约数2 最小公约数3 进制转换4 阶乘统计阶乘尾部0的个数5 字符串加法减法二进制加法6 多数投票问题数组中出现次数多于n/2的元素7 相遇问题改变数组元素使所有元素都相同1 最大公约数 欧几里得算法&#xff1a;两个整数的最大公约数等于其中较小的那个数和两数相除余…

Linux内核设计与实现---进程地址空间

进程地址空间1 内存描述符分配内存描述符销毁内存描述符mm_struct与内核线程2 内存区域VMA标志VMA操作内存区域的树形结构和内存区域的链表结构3 操作内存区域find_vma()find_vma_prev()find_vma_intersection()4 mmap()和do_mmap()&#xff1a;创建地址空间mmap&#xff08;&a…

JavaScript中带有示例的Math.log10()方法

JavaScript | Math.log10()方法 (JavaScript | Math.log10() Method) Math operations in JavaScript are handled using functions of math library in JavaScript. In this tutorial on Math.log10() method, we will learn about the log10() method and its working with e…

JSP技术

一、jsp脚本和注释 jsp脚本&#xff1a; 1&#xff09;<%java代码%> ----- 内部的java代码翻译到service方法的内部 2&#xff09;<%java变量或表达式> ----- 会被翻译成service方法内部out.print() 3&#xff09;<%!java代码%> ---- 会被翻译成servlet的成…

EL技术

1&#xff0e;EL 表达式概述 EL&#xff08;Express Lanuage&#xff09;表达式可以嵌入在jsp页面内部&#xff0c;减少jsp脚本的编写&#xff0c;EL 出现的目的是要替代jsp页面中脚本的编写。 2&#xff0e;EL从域中取出数据(EL最重要的作用) jsp脚本&#xff1a;<%requ…

SVN+AnkhSVN端配置

对于ankhSVN我想很多人不陌生&#xff0c;因为经常使用&#xff0c;但是我还是发现很多人并不怎么会配置&#xff0c;或者完全不知道其需要配置&#xff0c;如果不配置的话&#xff0c;当两个人同时需要修改某个文件的时候就容易中弹了。SVN默认是不支持“锁定-编辑-解锁”的&a…

Linux内核设计与实现---模块

模块1 构建模块放在内核源代码树中放在内核代码外2 安装模块3 产生模块依赖性4 载入模块5 管理配置选项6 模块参数7 导出符号表Linux内核是模块化组成的&#xff0c;它允许内核在运行时动态地向其中插入或从中删除代码。 与开发的内核核心子系统不同&#xff0c;模块开发更接近…

Linux内核设计与实现---kobject sysfs

kobject sysfs1 kobject2 ktype3 kset4 subsystem5 别混淆了这些结构体6 管理和操作kobject7 引用计数kref8 sysfssysfs中添加和删除kobject向sysfs添加文件9 内核事件层2.6内核增加了一个引人注目的新特性—同一设备模型。设备模型提供了独立的机制专门表示设备&#xff0c;并…

开发Windows Mobile今日插件 -- 内存电量,桌面便笺,桌面记单词

本篇文章讲解的是开发 Windows Mobile 上的今日插件。关于是今日插件&#xff0c;在 PPC 或者 SP SDK 的帮助文档中有相关的章节介绍&#xff0c;在网络上也有一些帖子和资源讲解。在这里简要回顾一下。今日插件就是在windows mobile的桌面上显示的条目&#xff0c;例如系统提供…

算法---递归

递归结题三部曲 何为递归&#xff1f;程序反复调用自身即是递归。 我自己在刚开始解决递归问题的时候&#xff0c;总是会去纠结这一层函数做了什么&#xff0c;它调用自身后的下一层函数又做了什么…然后就会觉得实现一个递归解法十分复杂&#xff0c;根本就无从下手。 相信…

给定条件找最小值c语言程序_根据给定条件最小化n的最小步骤

给定条件找最小值c语言程序Problem statement: 问题陈述&#xff1a; Given a number n, count minimum steps to minimize it to 1 performing the following operations: 给定数字n &#xff0c;执行以下操作&#xff0c;计算最少的步骤以将其最小化为1&#xff1a; Operat…

那个年代的苏联歌曲

小时候&#xff0c;不时听父亲提起电影《这里的黎明静悄悄》&#xff0c;怎么也想不到如此美丽的名字为什么要和战争联系起来。后来在大学看了这部电影之后&#xff0c;开始认为这名字是合适的&#xff0c;因为电影讲的是女性——战场中的女性&#xff0c;各自都怀揣着爱情去保…

linux系统编程---进程总结

进程控制总结1 进程创建的三种方式forkvfrokclone2 进程终止进程正常退出returnexit_exit进程异常退出进程收到某个信号&#xff0c;而该信号使进程终止abort3 进程等待进程等待的方法waitwaitpid4 进程替换替换原理替换函数制作一个简单的shell1 进程创建的三种方式 参考文章…

银行账务转账系统(事务处理)

流程如下&#xff1a; 创建项目工程如下&#xff1a; transfer包下的代码如下&#xff1a; package beyond.transfer.dao;import java.sql.Connection; import java.sql.SQLException;import org.apache.commons.dbutils.QueryRunner;import beyond.utils.DataSourceUtils;pu…

【msdn wpf forum翻译】TextBox中文本 中对齐 的方法

原文链接&#xff1a;http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/49864e35-1dbf-4292-a361-93f1a8400558问题&#xff1a;TextBox中文本中对齐&#xff0c;使用 TextBox.HorizontalContentAlignment"Center"行不通&#xff08;TextBox.VerticalConte…

c语言 函数的参数传递示例_C语言中带有示例的remove()函数

c语言 函数的参数传递示例C语言中的remove()函数 (remove() function in C) The remove() function is defined in the <stdio.h> header file. remove()函数在<stdio.h>头文件中定义。 Prototype: 原型&#xff1a; int remove(const char* filename);Parameter…

使用ThreadLocal绑定连接资源(事务)

dao层代码如下&#xff1a; package beyond.transfer.dao;import java.sql.Connection; import java.sql.SQLException;import org.apache.commons.dbutils.QueryRunner;import beyond.utils.DataSourceUtils; import beyond.utils.MyDataSourceUtils;public class TransferDa…

算法---栈和队列

栈和队列1 栈栈的顺序存储栈的链式存储2 队列队列的顺序存储队列的链式存储3 栈和队列的应用用栈实现队列用队列实现栈最小栈1 栈 参考文章&#xff1a; https://zhuanlan.zhihu.com/p/346164833 https://zhuanlan.zhihu.com/p/120965372#:~:text%E6%A0%88%E6%98%AF%E4%B8%80%…