第789讲网站界面设计

上传人:re****.1 文档编号:570803417 上传时间:2024-08-06 格式:PPT 页数:78 大小:1.21MB
返回 下载 相关 举报
第789讲网站界面设计_第1页
第1页 / 共78页
第789讲网站界面设计_第2页
第2页 / 共78页
第789讲网站界面设计_第3页
第3页 / 共78页
第789讲网站界面设计_第4页
第4页 / 共78页
第789讲网站界面设计_第5页
第5页 / 共78页
点击查看更多>>
资源描述

《第789讲网站界面设计》由会员分享,可在线阅读,更多相关《第789讲网站界面设计(78页珍藏版)》请在金锄头文库上搜索。

1、Linux内核窥视2李春强Linux内核基本概念系统调用内存管理进程管理虚拟文件系统(VFS) VFS基本概念主要对象类型存储介质管理操作具体磁盘根文件系统的挂载VFS主要系统调用进程间通信虚拟文件系统lVFS是一个软件层,是用户应用程序与具体文件系统实现之间的抽象层:对用户界面:一组标准的、抽象的文件操作,以系统调用提供,如read()、write()、open()等。对具体文件系统界面:主体是file_operations结构,全是函数指针,提供函数跳转表。VFS在一个简单文件复制操作中的作用l假设用户输入shell命令:$ cp /floppy/TEST /tmp/test 在cp命令中

2、,它通过VFS提供的系统调用接口进行文件操作。VFS支持的文件系统类型lVFS支持三种主要类型的文件系统:基于磁盘的文件系统:它们管理在本地磁盘分区中可用的存储空间。包括:ext2、ext3、ReiserFS、 MINIX、 MS-DOS、 NTFS 、 VFAT 、 DVD文件系统、 JFS 等等。网络文件系统:用于访问属于其他网络计算机的文件系统所包含的文件NFS、Coda、AFS、SMB、NCP特殊文件系统不同于上述两大类,不管理具体的磁盘空间如/procl对象关系图lVFS有下列主要对象类型:超级块对象(superblock )存放文件系统相关信息:例如文件系统控制块索引节点对象(in

3、ode )存放具体文件的一般信息:文件控制块/inode目录项对象(dentry )存放目录项与文件的链接信息文件对象(file )存放已打开的文件和进程之间交互的信息l存储介质对文件的管理 以ext2为例,涉及的对象有: - 引导块 - 磁盘超级块 在设备上的逻辑位置是固定的 -文件的组织和管理信息 即索引节点ext2_inode - 文件中的数据 包括目录的内容,即目录项ext2_dir_entry_2l各种结构在内存和磁盘中的对应关系 super_block 对应 磁盘超级块 inode 对应 索引节点ext2_inode dentry 对应 目录项ext2_dir_entry_2l文件

4、系统的安装:从一个存储设备上读入超级块,在内存中建立起一个super_block结构。再将此设备上的根目录与文件系统中的空白目录挂上钩。l每个文件都有目录项和索引节点在磁盘上,只有在需要时才在内存中建立起相应的dentry和inode结构。l文件系统用的数据结构表示 struct file_system_type const char *name; int fs_flags; struct super_block *(*read_super) (struct super_block *, void *, int); struct module *owner; struct file_syste

5、m_type * next; struct list_head fs_supers; ;l注册:实际上将表示各实际文件系统的 file_system_type 数据结构的实例化,然后挂接在file_systems链表中lrootfs文件系统的注册struct file_system_type rootfs_fs_type = name: rootfs, read_super: ramfs_read_super, fs_flags: FS_NOMOUNT|FS_LITTER, owner: THIS_MODULE, ;init_rootfs() 通过调用 register_filesystem(

6、&rootfs_fs_type)函数来完成rootfs 文件系统注册的 文件系统的注册l安装一个特殊的文件系统rootfs建立“/”目录:通过init_mount_tree()函数实现lInit_mount_tree()函数主要做两件事情函数会调用 do_kern_mount(“rootfs”, 0, “rootfs”, NULL) 来挂载前面已经注册了的 rootfs 文件系统init_mount_tree() 函数会为系统最开始的进程(即 一号进程init)准备它的进程task_struct中的namespace 成员 init_mount_tree() 这个函数为 VFS 建立了根目录

7、/,而一旦有了根,那么这棵数就可以发展壮大,比如可以通过系统调用 sys_mkdir 在这棵树上建立新的叶子节点等 VFS 目录树的建立目录树的建立 l文件系统安装将某一设备(dev_name)上某一文件系统(file_system_type)安装到VFS目录树上的某一安装点(dir_name) l安装之后的效果将对 VFS 目录树中某一目录的操作转化为具体安装到其上的实际文件系统的对应操作,最终要由目录或文件所对应的 inode 结构中的 i_op 和 i_fop 所指向的函数表中对应的函数来执行 l通过系统调用sys_mount()-do_mount() 实现调用 path_lookup(

8、) 函数来得到安装点的相关信息调用 do_add_mount() 函数来向 VFS 树中安装点 “/dev ” 安装一个实际的文件系统 l安装根文件系统同普通文件系统安装类似,只是安装点为”/”安装完成之后,必须将创建VFS跟节点时”/”的一号进程init的根目录转化成安装上去的 ext2 文件系统的根目录数据结构安装一个文件系统安装一个文件系统 l从路径名到目标节点 根据给定的文件路径名在内存中找到或建立代表着目标文件或目录的dentry结构和inode结构l在进程与文件之间建立起连接文件打开文件打开文件读写l文件的读和写文件打开后,才能对文件进行读/写。VFS所处理的系统调用mount、u

9、mount:挂载/卸载文件系统sysfs :获取文件系统信息statfs、fstatfs、ustat :获取文件系统统计信息chroot :更改根目录chdir、fchdir、getcwd :操纵当前工作目录mkdir、rmdir :创建/删除目录getdents、readdir 、link 、unlink 、rename :对目录项进行操作readlink 、symlink :对符号链接进行操作chown 、fchown 、lchown :更改文件所有者chmod 、fchmod 、utime :更改文件属性open、close、create Linux 基本概念系统调用内存管理进程管理虚拟

10、文件系统(VFS)进程间通信进程间通信机制管道信号机制报文队列共享内存信号量套接字Linux进程间通信1Linux进程间通信2管道(Pipe)及有名管道(named pipe):管道用在具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信; 信号(Signal):信号是比较复杂的通信方式,用于通知接受进程有某种事件发生,除了用于进程间通信外,进程还可以发送信号给进程本身;报文(Message)队列(消息队列):报文队列是消息的链接表,包括Posix消息队列system V消息队列。消息队列克服了信号承载信息量少,管道只能承载

11、无格式字节流以及缓冲区大小受限等缺点。 Linux进程间通信3共享内存:使得多个进程可以访问同一块内存空间,是最快的可用IPC形式。是针对其他通信机制运行效率较低而设计的。往往与其它通信机制,如信号量结合使用,来达到进程间的同步及互斥。 信号量(semaphore): 主要作为进程间以及同一进程不同线程之间的同步手段。 套接口(Socket):更为一般的进程间通信机制,可用于不同机器之间的进程间通信。起初是由Unix系统的BSD分支开发出来的,但现在一般可以移植到其它类Unix系统上:Linux和System V的变种都支持套接字。 管道实例l通俗地说,它们就是连接两个实体的一个单向连接器。例

12、如,请看下面的命令:ls -1 | wc -l 这个例子就在两个命令之间建立了一根管道;命令ls执行后产生的输出作为了命令wc的输入。匿名管道l必须用在有亲缘关系的进程之间,如父子进程之间或兄弟进程之间;(为什么?)l遵循“先入先出”(FIFO)的规则l管道是单向的,如果需要双向通信,则必须两个管道l管道两端以“匿名文件”的形式出现在相关的进程中,而这个文件,不是采用open打开的,而是pipe系统调用创建并打开的,只存在于内存中匿名管道程序示例#define MAX_LINE 80 #define PIPE_STDIN 0 #define PIPE_STDOUT 1 int main() c

13、onst char *string= A sample message.; int ret, myPipe2; char bufferMAX_LINE+1; /* 建立管道建立管道 */ ret = pipe( myPipe ); if (ret = 0) ret = fork(); if ( ret = 0) /* 将消息写入管道将消息写入管道 */ write( myPipePIPE_STDOUT, string, strlen(string) ); else /* 从管道读取消息从管道读取消息 */ ret = read( myPipePIPE_STDIN, buffer, MAX_LI

14、NE ); /* 利用利用Null结束字符串结束字符串 */ buffer ret = 0; printf(%sn, buffer); 命名管道l用于任意进程间的通信l管道两端以“命名文件”的形式出现,也就是说文件是在实际文件系统中看得到的,这样所有进程都可以访问这样的文件。lFIFO文件类型,也就是不支持文件内部读写指正的移动(不支持lseek系统调用)l通过mkdifo函数创建FIFO文件,也即命名管道文件l管道读写两端通过打开这个被创建的文件就可以进行通信#include #include int mkfifo( const char *pathname, mode_t mode );

15、命名管道程序示例l管道的创建 int ret; ret = mkfifo( /tmp/cmd_pipe, S_IFIFO | 0666 ); if (ret = 0) / 成功建立命名管道 else / 创建命名管道失败 l管道的发送方 pfp = fopen( /tmp/cmd_pipe, w+ ); ret = fprintf( pfp, Heres a test string!n ); l管道的接收方 pfp = fopen( /tmp/cmd_pipe, r ); ret = fgets( buffer, MAX_LINE, pfp ); 信号1l信号是一种软中断机制,并不是专门为进程

16、间通信而实现,也可以用在内核和进程之间的通信。中断中断信号信号说法说法处理器收到中断请求进程收到信号中断源中断源其它处理器、外设、处理器本身其它进程、內核、本进程同异步同异步异步,指令结束后检测异步,系统空间返回用户空间前夕检测屏蔽屏蔽可屏蔽可屏蔽信号的管理数据结构l通常使用一个数字来标识一个信号。l信号可以被发送到一个进程或一组进程。l64种信号早期Unix系统只定义了32种信号,但存在缺陷,为了弥补缺陷,扩充到了64种,我们称前32种信号为“不可靠信号”,后32种为“可靠信号”l使用信号的两个主要目的是:通知进程已经发生了特定的事件。强迫进程执行相应的信号处理程序(系统默认或者用户自己定义

17、)。信号2信号处理函数的安装l两个目的:- 进程将要处理哪个信号- 收到该信号时,进程将执行何种操作 l对于未安装的信号,进程将执行信号的默认动作。l用户可用下面两个函数安装信号:signal(signum, handler)sigaction(signum, act, oact)l信号安装的具体体现:将handler或act赋值给current-sighand-actionsig-1 信号发送函数int kill(pid_t pid,int signo) 将信号发送给一个或一组进程。 对于pid的值 1. 0,发送信号给指定的进程; 2. = 0,把信号发送给同组的所有进程; 3. = -1

18、,把信号发送给除0号、1号以及current之外的所有进程; 4. -1,把信号发送给指定的进程组中的所有的进程。int sigqueue(pid_t pid, int sig, const union sigval val) 只能向一个进程发送信号,支持发送信号带附加信息。信号的发送l信号可以发送给指定的一个或者多个进程。 ltask_struct中有个pending域:struct sigpending pending;struct sigpendingstruct list_head list;sigset_t signal;其中,signal是标识未处理信号集的位图, list是sig

19、queue队列。l信号发送具体体现:在指定进程task_struct的未处理信号集中添加该信号 。 l可靠信号和不可靠信号:是否支持排队struct sigqueue struct list_head list; int flags; siginfo_t info; struct user_struct *user; 信号的响应l响应时机:l响应方式: 1. 显式的忽略信号 2. 执行系统默认的缺省操作,可以是:- Terminate:进程被杀死- Dump:进程被杀死,且如果可能,创建包含进程上下文的可用于调试的core文件- Ignore:简单的忽略信号- Stop:进程被停止,状态置为T

20、ASK_STOPPED- Continue:如果进程被挂起,则状态置为TASK_RUNNING。否则忽略该信号3. 捕获信号- 为了执行用户希望的对某个事件的处理,可以由用户指定某个信号的处理函数。ldo_signal() 一位一位的检查当前被挂起的非阻塞信号,调用sighand中action数组对应的处理方法: - 如果是SIG_IGN(忽略信号),忽略信号,返回; - 如果是SIG_DFL(缺省操作),找到对应的缺省处理方 式; - 如果信号有用户注册的处理程序,就调用handle_signal()强迫执行该处理程序。lhandle_signal() handle_signal运行在内核态

21、,而信号处理程序在用户态的代码段中,运行在用户态。问题:1. 必须返回用户态执行信号处理程序;2. 必须按照原来进入内核的方式返回用户态;3. 一旦返回用户态,内核堆栈就被清空,如何保存内核堆栈的内容lLinux采用的解决办法:在用户空间堆栈中为信号处理程序的执行预先创建一个栈帧,栈帧中包括一个作为局部变量的数据结构,我们叫sigframe,并把系统空间堆栈中的“原始栈帧”保存到这个数据结构中;在sigframe中插入对系统调用sigreturn()的调用;将系统空间堆栈中“原始栈帧”修改成为执行信号处理程序所需的栈帧;“返回”到用户空间,但是却执行信号处理程序;信号处理程序执行完毕以后,通过

22、系统调用sigreturn()重返系统空间;在系统调用sigreturn()中从用户空间回复“原始栈帧”再返回到用户空间,继续执行原先的用户程序l管道的缺点:所载送的信息是没有格式的字节流。加入一个进程要发送两端文字给另一个进程,两端文字连成片,接收进程无法知道两端文字的分界;载送的是无格式字节流,而且是先进先出,缺乏控制手段,如没有办法根据优先级来决定处理的先后顺序;管道机制的缓冲区大小是有限制的,当被写满了,而还没有读走,则发送方进入睡眠;运行效率低,因为管道机制的开销不小;l信号的缺点承载的信息量很少管道和信号的缺点l三种机制合一报文传递一个进程可以通过系统调用设立一个报文队列,任何进程

23、可以通过系统调用向这个队列发送“消息”或从队列接收“消息”。共享内存 一个进程可以通过系统调用设立一片共享内存去,然后其他进程可以通过系统调用将该存储区映射到自己的地址空间中。此后,就可以想正常的内存访问一样读写该共享区间。信号量 用来多线程多进程同步的,一个线程或进程完成了某一个动作就通过信号量告诉别的线程或进程,别的线程或进程再进行某些动作。SystemV进程间通信机制System V IPC的共同特征的共同特征标识符与关符与关键字字引用引用IPC对象:象:标识符符创建建IPC对象象时指定关指定关键字字(key_t key;)key的的选择;预定定义常数常数IPC_PRIVATE;ftok

24、函数函数内核将关内核将关键字字转换成成标识符符许可可权结构构和文件和文件类比比struct ipc_permSV IPC 系系统调用用功能功能消息消息队列列信号量信号量共享内存共享内存分配一个分配一个IPC对象,象,获得得对IPC的的访问msggetsemgetshmgetIPC操作操作: 发送送/接收消息,接收消息,信号量操作,信号量操作,连接接/释放共放共享内存享内存msgsnd/msgrcvsemopshmat/shmdtIPC控制:控制:获得得/修改状修改状态信息,取消信息,取消IPCmsgctlsemctlshmctl信号量信号量并并发程序程序设计互斥和同步互斥和同步PV操作操作(原

25、原语) P操作:用于等待操作:用于等待V操作:用于信号操作:用于信号PV操作和信号量操作和信号量procedure p(var s:samephore) s.value=s.value-1; if (s.value0) sleep(s.queue); procedure v(var s:samephore) s.value=s.value+1; if (s.value=0) wakeup(s.queue); 一个理一个理论性的例子性的例子Linux的信号量机制的信号量机制semaphore setstruct semid_ds struct ipc_perm sem_perm; struct

26、sem *sem_base; /* 指向信号量集合的指指向信号量集合的指针 */ time_t sem_otime; /* 最后一次操作的最后一次操作的时间 */ time_t sem_ctime; /* 最后一次改最后一次改变此此结构的构的时间 */ unsigned short sem_nsems; /* 集合中信号量个数集合中信号量个数*/Linux的信号量机制的信号量机制struct sem pid_t sempid; /* 最后操作最后操作该信号量的信号量的进程程ID */ unsigned short semncnt ; /* 等待等待对该信号量信号量执行行P 操作的操作的进程数程

27、数 */ unsigned short semzcnt; /* 等待等待semval为0的的进程数程数 */ unsigned short semval; /* 信号量当前信号量当前值 */信号量系信号量系统调用用#include #include #include int semget(key_t key, int nsems, int semflg);int semop(int semid, struct sembuf *sops, unsigned nsops);int semctl(int semid, int semnum, int cmd, .);semget函数函数 功能:功能:

28、创建一个新信号量或取得一个已有信号量的建一个新信号量或取得一个已有信号量的 标志符。志符。函数原型函数原型为int semget(key_t key, int nsems, int semflg);“key” 参数参数预定定义常数常数IPC_PRIVATE;约定的关定的关键字字ftok函数函数“semflg” 参数参数设置置访问权限限(低低9位位)IPC_CREAT, IPC_EXCL 按位或按位或“nsems”指定需要的信号量数目,几乎指定需要的信号量数目,几乎总是取是取值为1。#include key_t ftok(const char *path,int id);semget函数(函数(

29、续) sem_id = semget(key_t)1234, 1, 0666 | IPC_CREAT);semop函数函数功能:改变信号量的值功能:改变信号量的值函数原型函数原型为int semop(int semid, struct sembuf *sops, size_t nsops);“sops” 参数参数struct sembuf unsigned short sem_num; /* 信号量信号量编号号 */ short sem_op; /* 信号量操作信号量操作 */ short sem_flg; /* 操作操作标志志 */nsops参数参数结构数构数组的元素个数的元素个数semop

30、函数(函数(续)sem_flg用于用于对操作操作进行适当的控制,主要行适当的控制,主要有有2个控制个控制标志。志。IPC_NOWAIT 当指定的操作不能完成当指定的操作不能完成时,进程不等待立即返程不等待立即返回,返回回,返回值为-1,errno置置为EAGAIN。SEM_UNDO(建(建议) 进程退出程退出时,执行信号量解除(行信号量解除(undo)操作。操作。semop函数(函数(续)int semaphore_p(void) struct sembuf sem_b; sem_b.sem_num = 0; sem_b.sem_op = -1; /* P() */ sem_b.sem_flg

31、 = SEM_UNDO; if (semop(sem_id, &sem_b, 1) = -1) fprintf(stderr, semaphore_p failedn); return(0); return(1);semop函数(函数(续)static int semaphore_v(void) struct sembuf sem_b; sem_b.sem_num = 0; sem_b.sem_op = 1; /* V() */ sem_b.sem_flg = SEM_UNDO; if (semop(sem_id, &sem_b, 1) = -1) fprintf(stderr, semaph

32、ore_v failedn); return(0); return(1);semctl函数函数功能:直接控制信号量信息功能:直接控制信号量信息函数原型函数原型为:int semctl(int semid, int semnum, int cmd, .);第第4个参数(可个参数(可选)union semun int val; /*用于用于SETVAL命令,指明要命令,指明要设置的置的值*/ struct semid_ds *buf; /*用于用于IPC_STAT/IPC_IPC_SET命令,用来存放信号量集合数据命令,用来存放信号量集合数据结构构*/ unsigned short *array;

33、 /*用于用于GETALL/SETALL命令,用来存放所命令,用来存放所获得的或是要得的或是要设置信号量集合置信号量集合中所有信号量的中所有信号量的值*/ arg;“cmd” 参数参数semctl函数(函数(续)“cmd” parameterIPC_STAT: 对指定的信号量指定的信号量标识返回返回arg.semid_ds结构中的当前构中的当前值IPC_SET: 在在进程有足程有足够权限的前提下,把信号量集合限的前提下,把信号量集合的当前关的当前关联值置置为arg.semid_ds结构构给出的出的值IPC_RMID: 删除信号量集合除信号量集合SETVAL: 设置信号量集合中由置信号量集合中由

34、semnum指定的指定的单个信个信号量的号量的值(设为arg.val)semctl函数(函数(续)int set_semvalue(void) union semun sem_union; sem_union.val = 1; if (semctl(sem_id, 0, SETVAL, sem_union) = -1) return(0); return(1);void del_semvalue(void) union semun sem_union; if (semctl(sem_id, 0, IPC_RMID, sem_union) = -1) fprintf(stderr, Failed

35、 to delete semaphoren);Examples一个完整的一个完整的实例例sem1.c(进程互斥程互斥)semun.h#if defined(_GNU_LIBRARY_) & !defined(_SEM_SEMUN_UNDEFINED) /* union semun is defined by including */#else /* according to X/OPEN we have to define it ourselves */ union semun int val; /* value for SETVAL */ struct semid_ds *buf; /* b

36、uffer for IPC_STAT, IPC_SET */ unsigned short int *array; /* array for GETALL, SETALL */;#endifstatic int set_semvalue(void) union semun sem_union; sem_union.val = 1; if (semctl(sem_id, 0, SETVAL, sem_union) = -1) return(0); return(1);static void del_semvalue(void) union semun sem_union; if (semctl(

37、sem_id, 0, IPC_RMID, sem_union) = -1) fprintf(stderr, Failed to delete semaphoren);static int semaphore_p(void) struct sembuf sem_b; sem_b.sem_num = 0; sem_b.sem_op = -1; /* P() */ sem_b.sem_flg = SEM_UNDO; if (semop(sem_id, &sem_b, 1) = -1) fprintf(stderr, semaphore_p failedn); return(0); return(1)

38、;static int semaphore_v(void) struct sembuf sem_b; sem_b.sem_num = 0; sem_b.sem_op = 1; /* V() */ sem_b.sem_flg = SEM_UNDO; if (semop(sem_id, &sem_b, 1) = -1) fprintf(stderr, semaphore_v failedn); return(0); return(1);#include #include #include #include #include #include #include semun.hstatic int s

39、et_semvalue(void);static void del_semvalue(void);static int semaphore_p(void);static int semaphore_v(void);static int sem_id;int main(int argc, char *argv) int i; int pause_time; char op_char = O; srand(unsigned int)getpid(); sem_id = semget(key_t)1234, 1, 0666 | IPC_CREAT); if (argc 1) if (!set_sem

40、value() fprintf(stderr, Failed to initialize semaphoren); exit(EXIT_FAILURE); op_char = X; sleep(2); for(i = 0; i 1) sleep(10); del_semvalue(); exit(EXIT_SUCCESS);共享内存共享内存共享内存共享内存共享内存是内核共享内存是内核为进程程创建的一个特殊内存段,建的一个特殊内存段,它将出它将出现在自己的地址空在自己的地址空间中,其它中,其它进程可以程可以将同一段共享内存将同一段共享内存连接接(attach)到自己的地址到自己的地址空空间效率最

41、高的效率最高的进程程间通信方式通信方式不提供任何同步功能不提供任何同步功能共享内存示意图共享内存示意图进程进程A的的虚拟地址空间虚拟地址空间进程进程B的的虚拟地址空间虚拟地址空间物理内存物理内存共享存储共享存储shmid_ds结构构共享内存系统调用共享内存系统调用#include #include #include int semget(key_t key, int size, int flag);void *shmat(int shmid, void *addr, int flag);int shmdt(void *addr);int shmctl(int shmid, int cmd, s

42、truct shmid_ds *buf);shmget函数函数#include #include #include int semget(key_t key, size_t size, int shmflag);成功返回一个共享内存成功返回一个共享内存成功返回一个共享内存成功返回一个共享内存标识标识符,失符,失符,失符,失败败返回返回返回返回1 1第一个参数第一个参数key为共享内存段命名。共享内存段命名。第二个参数第二个参数size为需要共享的内存容量。(如果需要共享的内存容量。(如果key已存在已存在时,必,必须不大于不大于该共享内存段的大小)共享内存段的大小)第三个参数第三个参数设置置访

43、问权限限(低低9位)和位)和IPC_CREAT, IPC_EXCL 按位或。按位或。功能:获得或创建一个共享内存标识符。功能:获得或创建一个共享内存标识符。shmget函数(续)函数(续)shmid = shmget(key_t)1234, sizeof(struct shared_use_st),0666 | IPC_CREAT);shmat函数函数#include #include #include void *shmat(int shm_id, const void *addr, int shmflg) ;成功返回共享存成功返回共享存储段段连接的接的实际地址,失地址,失败返回返回-1第一

44、个参数第一个参数shm_id为shmget返回的共享内存返回的共享内存标识符。符。第二个参数第二个参数shm_addr指明共享内存段要指明共享内存段要连接到的地址,通常是接到的地址,通常是一个空指一个空指针,表示,表示让系系统来来选择共享内存出共享内存出现的地址。的地址。第三个参数第三个参数shmflg可以设置两个标志位SHM_RND(与(与shm_addr联合使用,控制内存合使用,控制内存连接的地址)接的地址)SHM_RDONLY,要要连接的共享内存段是只接的共享内存段是只读的。的。功能:将共享内存段连接到一个进程的地址空间中。功能:将共享内存段连接到一个进程的地址空间中。shmdt函数函数

45、#include #include #include int shmdt(const void *shmaddr) ;其中其中shmaddr为shmat返回的地址。返回的地址。功能:将共享内存从当前进程中分离。功能:将共享内存从当前进程中分离。shmctl函数函数 int shmctl(int shm_id, int command, struct shmid_ds *buf) ; 成功返回成功返回0,失,失败返回返回-1功能:查看及修改共享内存段的功能:查看及修改共享内存段的shmid_ds结构,结构,删除该结构以及相连的共享存储段标识。删除该结构以及相连的共享存储段标识。第二个参数第二个参

46、数commad取值:取值: IPC_STAT buf指向当前共享内存段的指向当前共享内存段的shmid_ds结构结构 IPC_SET 把共享内存段的当前关联值设置为把共享内存段的当前关联值设置为shmid_ds结构结构 给出的值给出的值IPC_RMID 从系统中删除该共享存储段。从系统中删除该共享存储段。例例1:生产者程序:生产者程序include include #include #include #define SHMSZ 27int main(void) char c; int shimd; key_t key; char *shm ,*s; key=5678; if(shmid=shm

47、get(key,SHMSZ,IPC_CREAT| 0666)0) exit(EXIT_FAILURE); if(shm=shmat(shmid,NULL,0)=(char *)-1) exit(EXIT_FAILURE); s=shm; for(c=a;c=z;c+) *s+=c; *s=NULL; while(*shm!=*) sleep(1); exit(EXIT_SUCCESS);include include #include #include #define SHMSZ 27int main(void) int shimd; key_t key; char *shm ,*s; key

48、=5678; if(shmid=shmget(key,SHMSZ,0666)written_by_you = 1) sleep(1); printf(waiting for client.n); printf(Enter some text: ); fgets(buffer, BUFSIZ, stdin); strncpy(shared_stuff-some_text, buffer, TEXT_SZ); shared_stuff-written_by_you = 1; if (strncmp(buffer, end, 3) = 0) running = 0; if (shmdt(shared

49、_memory) = -1) fprintf(stderr, shmdt failedn); exit(EXIT_FAILURE); exit(EXIT_SUCCESS);例例2:消费者程序:消费者程序int main() int running = 1; void *shared_memory = (void *)0; struct shared_use_st *shared_stuff; int shmid; srand(unsigned int)getpid(); shmid = shmget(key_t)1234, sizeof(struct shared_use_st), 0666

50、| IPC_CREAT); if (shmid = -1) fprintf(stderr, shmget failedn); exit(EXIT_FAILURE); /* We now make the shared memory accessible to the program. */ shared_memory = shmat(shmid, (void *)0, 0); if (shared_memory = (void *)-1) fprintf(stderr, shmat failedn); exit(EXIT_FAILURE); printf(Memory attached at

51、%Xn, (int)shared_memory); shared_stuff = (struct shared_use_st *)shared_memory; shared_stuff-written_by_you = 0; while(running) if (shared_stuff-written_by_you) printf(You wrote: %s, shared_stuff-some_text); sleep( rand() % 4 ); /* make the other process wait for us ! */ shared_stuff-written_by_you

52、= 0; if (strncmp(shared_stuff-some_text, end, 3) = 0) running = 0; if (shmdt(shared_memory) = -1) fprintf(stderr, shmdt failedn); exit(EXIT_FAILURE); if (shmctl(shmid, IPC_RMID, 0) = -1) fprintf(stderr, shmctl(IPC_RMID) failedn); exit(EXIT_FAILURE); exit(EXIT_SUCCESS);Thank you!l参考资料1.Linux内核源代码导读陈香兰 著.2.LINUX内核源代码情景分析毛德操 胡希明 著.3.C-SKY MMU Micro-Architecture杭州中天微 著.4.linux2.6.30 内核源代码.

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 建筑/环境 > 施工组织

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号