当前位置:文档之家› 内存共享

内存共享

内存共享
内存共享

共享内存函数由shmget、shmat、shmdt、shmctl四个函数组成。下面的表格列出了这四个函数的函数原型及其具体说明。

1. shmget函数原型

shmget(得到一个共享内存标识符或创建一个共享内存对象)

头文件#include #include

函数说明得到一个共享内存标识符或创建一个共享内存对象并返回共享内存标识符

int shmget(key_t key, size_t size, int shmflg)

函数传key

0(IPC_PRIVATE):会建立新共享内存对象

大于0的32位整数:视参数shmflg来确定操作。通常要求

此值来源于ftok返回的IPC键值

入值size

大于0的整数:新建的共享内存大小,以字节为单位

0:只获取共享内存时指定为0

shmflg

0:取共享内存标识符,若不存在则函数会报错

IPC_CREAT:当shmflg&IPC_CREAT为真时,如果内核

中不存在键值与key相等的共享内存,则新建一个共享内

存;如果存在这样的共享内存,返回此共享内存的标识符

IPC_CREAT|IPC_EXCL:如果内核中不存在键值与key相

等的共享内存,则新建一个消息队列;如果存在这样的共享

内存则报错

函数返回值成功:返回共享内存的标识符

出错:-1,错误原因存于error中

加说明上述shmflg参数为模式标志参数,使用时需要与IPC对象存取权限(如0600)进行|运算来确定信号量集的存取权限

错误代EINVAL:参数size小于SHMMIN或大于SHMMAX EEXIST:预建立key所指的共享内存,但已经存在

码EIDRM:参数key所指的共享内存已经删除

ENOSPC:超过了系统允许建立的共享内存的最大值(SHMALL) ENOENT:参数key所指的共享内存不存在,而参数shmflg未设IPC_CREAT位

EACCES:没有权限

ENOMEM:核心内存不足

在Linux环境中,对开始申请的共享内存空间进行了初始化,初始值为0x00。

如果用shmget创建了一个新的消息队列对象时,则shmid_ds结构成员变量的值设置如下:

? shm_lpid、shm_nattach、shm_atime、shm_dtime设置为0。

? msg_ctime设置为当前时间。

? shm_segsz设成创建共享内存的大小。

? shmflg的读写权限放在shm_perm.mode中。

? shm_perm结构的uid和cuid成员被设置成当前进程的有效用户ID,gid和cuid成员被设置成当前进程的有效组ID。

2. shmat函数原型

shmat(把共享内存区对象映射到调用进程的地址空间)所需

头文件#include #include

函数说明连接共享内存标识符为shmid的共享内存,连接成功后把共享内存区对象映射到调用进程的地址空间,随后可像本地空间一样访问

函数

原型

void *shmat(int shmid, const void *shmaddr, int shmflg)

函数传入值msqid

共享内存标识符

shmaddr

指定共享内存出现在进程内存地址的什么位置,直接指

定为NULL让内核自己决定一个合适的地址位置

shmflg

SHM_RDONLY:为只读模式,其他为读写模式

函数返回值成功:附加好的共享内存地址

出错:-1,错误原因存于error中

附加说明fork后子进程继承已连接的共享内存地址。exec后该子进程与已连接的共享内存地址自动脱离(detach)。进程结束后,已连接的共享内存地址会自动脱离(detach)

错误

代码

EACCES:无权限以指定方式连接共享内存

EINVAL:无效的参数shmid或shmaddr

ENOMEM:核心内存不足3. shmdt函数原型

shmat(断开共享内存连接)

所需

头文件#include #include

函数说明与shmat函数相反,是用来断开与共享内存附加点的地址,禁止本进程访问此片共享内存

函数

原型

int shmdt(const void *shmaddr)

函数

传入

shmaddr:连接的共享内存的起始地址

函数返回值成功:0

出错:-1,错误原因存于error中

附加说明本函数调用并不删除所指定的共享内存区,而只是将先前用shmat函数连接(attach)好的共享内存脱离(detach)目前的进程

错误

代码

EINVAL:无效的参数shmaddr 4. shmctl函数原型

shmctl(共享内存管理)所需

头文件#include #include

函数

说明

完成对共享内存的控制

函数

原型

int shmctl(int shmid, int cmd, struct shmid_ds *buf)

函数传入值msqid

共享内存标识符

cmd

IPC_STAT:得到共享内存的状态,把共享内存的shmid_ds 结构复制到buf中

IPC_SET:改变共享内存的状态,把buf所指的shmid_ds 结构中的uid、gid、mode复制到共享内存的shmid_ds结构内

IPC_RMID:删除这片共享内存

buf

共享内存管理结构体。具体说明参见共享内存内核结构定

义部分

函数返回值成功:0

出错:-1,错误原因存于error中

错误EACCESS:参数cmd为IPC_STAT,确无权限读取该共享内存

代码EFAULT:参数buf指向无效的内存地址

EIDRM:标识符为msqid的共享内存已被删除

EINVAL:无效的参数cmd或shmid

EPERM:参数cmd为IPC_SET或IPC_RMID,却无足够的权限执行

共享内存应用范例

5. 父子进程通信范例

父子进程通信范例,shm.c源代码如下:

#include

#include

#include

#include

#include

#include

#define SIZE 1024

int main()

{

int shmid ;

char *shmaddr ;

struct shmid_ds buf ;

int flag = 0 ;

int pid ;

shmid = shmget(IPC_PRIVATE, SIZE, IPC_CREAT|0600 ) ; if ( shmid < 0 )

{

perror("get shm ipc_id error") ;

return -1 ;

}

pid = fork() ;

if ( pid == 0 )

{

shmaddr = (char *)shmat( shmid, NULL, 0 ) ;

if ( (int)shmaddr == -1 )

{

perror("shmat addr error") ;

return -1 ;

}

strcpy( shmaddr, "Hi, I am child process!\n") ;

shmdt( shmaddr ) ;

return 0;

} else if ( pid > 0) {

sleep(3 ) ;

flag = shmctl( shmid, IPC_STAT, &buf) ;

if ( flag == -1 )

{

perror("shmctl shm error") ;

return -1 ;

}

printf("shm_segsz =%d bytes\n", buf.shm_segsz ) ;

printf("parent pid=%d, shm_cpid = %d \n", getpid(),

buf.shm_cpid ) ;

printf("chlid pid=%d, shm_lpid = %d \n",pid , buf.shm_lpid ) ;

shmaddr = (char *) shmat(shmid, NULL, 0 ) ;

if ( (int)shmaddr == -1 )

{

perror("shmat addr error") ;

return -1 ;

}

printf("%s", shmaddr) ;

shmdt( shmaddr ) ;

shmctl(shmid, IPC_RMID, NULL) ;

}else{

perror("fork error") ;

shmctl(shmid, IPC_RMID, NULL) ;

}

return 0 ;

}

编译gcc shm.c –o shm。

执行 ./shm,执行结果如下:

shm_segsz =1024 bytes

shm_cpid = 9503

shm_lpid = 9504

Hi, I am child process!

6. 多进程读写范例

多进程读写即一个进程写共享内存,一个或多个进程读共享内存。下面的例子实现的是一个进程写共享内存,一个进程读共享内存。

(1)下面程序实现了创建共享内存,并写入消息。

shmwrite.c源代码如下:

#include

#include

#include

#include

#include

#include

typedef struct{

char name[8];

int age;

} people;

int main(int argc, char** argv)

{

int shm_id,i;

key_t key;

char temp[8];

people *p_map;

char pathname[30] ;

strcpy(pathname,"/tmp") ;

key = ftok(pathname,0x03);

if(key==-1)

{

perror("ftok error");

return -1;

}

printf("key=%d\n",key) ;

shm_id=shmget(key,4096,IPC_CREAT|IPC_EXCL|0600); if(shm_id==-1)

{

perror("shmget error");

return -1;

}

printf("shm_id=%d\n", shm_id) ;

p_map=(people*)shmat(shm_id,NULL,0);

memset(temp, 0x00, sizeof(temp)) ;

strcpy(temp,"test") ;

temp[4]='0';

for(i = 0;i<3;i++)

{

temp[4]+=1;

strncpy((p_map+i)->name,temp,5);

(p_map+i)->age=0+i;

}

shmdt(p_map) ;

return 0 ;

}

(2)下面程序实现从共享内存读消息。shmread.c源代码如下:

#include

#include

#include

#include

#include

#include

typedef struct{

char name[8];

int age;

} people;

int main(int argc, char** argv)

{

int shm_id,i;

key_t key;

people *p_map;

char pathname[30] ;

strcpy(pathname,"/tmp") ;

key = ftok(pathname,0x03);

if(key == -1)

{

perror("ftok error");

return -1;

}

printf("key=%d\n", key) ;

shm_id = shmget(key,0, 0);

if(shm_id == -1)

{

perror("shmget error");

return -1;

}

printf("shm_id=%d\n", shm_id) ;

p_map = (people*)shmat(shm_id,NULL,0);

for(i = 0;i<3;i++)

{

printf( "name:%s\n",(*(p_map+i)).name );

printf( "age %d\n",(*(p_map+i)).age );

}

if(shmdt(p_map) == -1)

{

perror("detach error");

return -1;

}

return 0 ;

}

(3)编译与执行

①编译gcc shmwrite.c -o shmwrite。

②执行./shmwrite,执行结果如下:

key=50453281

shm_id=688137

③编译gcc shmread.c -o shmread。

④执行./shmread,执行结果如下:

key=50453281

shm_id=688137

name:test1

age 0

name:test2

age 1

name:test3

age 2

⑤再执行./shmwrite,执行结果如下:

key=50453281

shmget error: File exists

⑥使用ipcrm -m 688137删除此共享内存。

共享内存+互斥量实现linux进程间通信

共享内存+互斥量实现linux进程间通信 一、共享内存简介 共享内存是进程间通信中高效方便的方式之一。共享内存允许两个或更多进程访问同一块内存,就如同malloc() 函数向不同进程返回了指向同一个物理内存区域的指针,两个进程可以对一块共享内存进行读写。 共享内存并未提供进程同步机制,使用共享内存完成进程间通信时,需要借助互斥量或者信号量来完成进程的同步。这里说一下互斥量与信号量的区别。互斥量用于线程的互斥,信号量用于线程的同步,这是互斥量与信号量的本质区别,其次信号量实现互斥量的功能。 本文结合个人实际项目需求,采用互斥量实现进程间访问共享内存的互斥,即同一时刻只能允许一个进程对共享内存进行写操作。 二、使用系统调用完成共享内存的申请、连接、分离和删除 共享内存函数由shmget、shmat、shmdt、shmctl四个函数组成。使用时需要包含#include 、#include 、#include 和。 1.共享内存的申请 使用shmget()完成共享内存的申请,函数原型如下: int shmget(key_t key, size_t size, int shmflg); key:共享内存的标识符,大于0的32位整数。若是父子关系的进程间通信,这个标识符用IPC_PRIVATE,若进程没有关系,可自行定义。 size:共享内存大小,单位Byte。 shmflg:共享内存的模式(mode),包括三部分,第一部分是:无指定标示符的共享内存是否创建,由0(只获取)或IPC_CREAT(未创建则新建)决定。第二部分:IPC_EXCL(若已创建,则报错)。第三部分:权限标识,由八进制表示,如0640,第一个0是八进制数标识,第一个6(4+2)表示拥有者的权限读和写,第二个4表示同组权限写,第3个0表示他人的权限。这三部分由算数或运算符|拼接组成shmflg,如IPC_CREAT|0640。 成功时返回共享内存的ID,失败时返回-1。 2.共享内存的连接 使用shmat()函数将已经申请好的共享连接到当前进程的地址空间,函数原型如下: void *shmat(int shmid, const void *shmaddr, int shmflg); shmid:共享内存标识符。 shmaddr:指定进程使用共享内存的起始地址,直接指定为NULL让内核自己决定一个合适的地址位置。 shmflg:SHM_RDONLY为只读模式,其他为读写模式,通常设置为NULL。 成功时,这个函数返回共享内存的起始地址。失败时返回-1。 3.共享内存的分离 使用sdmdt()函数将已连接的共享内存与进程分离,功能与shmat()相反,函数原型如下:int shmdt(const void *shmaddr); shmaddr:连接的共享内存的起始地址。成功时返回0。失败时返回-1。 4.共享内存的删除 shmctl() 控制对这块共享内存的使用,包括删除。函数原型如下: int shmctl(int shmid, int command, struct shmid_ds *buf); shmid:共享内存的ID。 command:是控制命令,IPC_STAT(获取共享内存的状态)、IPC_SET(改变共享内存的状态)IPC_RMID (删除共享内存)。

linux下共享内存

Linux下共享内存 SUNNY.MAN 共享内存允许两个或多个进程进程共享同一块内存(这块内存会映射到各个进程自己独立的地址空间) 从而使得这些进程可以相互通信,进程退出时会自动和已经挂接的共享内存区段分离,但是仍建议当进程不再使用共享区段时调用shmdt来卸载区段。注意,当一个进程分支出父进程和子进程时,父进程先前创建的所有共享内存区段都会被子进程继承。如果区段已经做了删除标记(在前面以IPC_RMID指令调用shmctl),而当前挂接数已经变为0,这个区段就会被移除。Linux中通过API函数shmget创建的共享内存一般都是在程序中使用shmctl来释放的,但是有时为了调试程序,开发人员可能通过Ctrl + C等方式发送中断信号来结束程序,此时程序申请的共享内存就不能得到释放,当然如果程序没有改动的话,重新运行程序时仍然会使用上次申请的共享内存,但是如果我们修改了程序,由于共享内存的大小不一致等原因会导致程序申请共享内存错误。因此,我们总是希望每次结束时就能释放掉申请的共享内存。 有两种方法可以用来释放共享内存: 第一种:如果总是通过Crtl+C来结束的话,可以做一个信号处理器,当接收到这个信号的时候,先释放共享内存,然后退出程序。 第二种:不管你以什么方式结束程序,如果共享内存还是得不到释放,那么可以通过linux命令ipcrm shm shmid来释放,在使用该命令之前可以通过ipcs -m命令来查看共享内存。 共享内存查看 使用ipcs命令,不加如何参数时,会把共享内存、信号量、消息队列的信息都

打印出来,如果只想显示共享内存信息,使用如下命令: [root@localhost ~]# ipcs –m 同样共享内存的大小也可以用ipcs –lm来查看它的上限下限。 shmget( ) 创建一个新的共享内存区段 取得一个共享内存区段的描述符 shmctl( ) 取得一个共享内存区段的信息 为一个共享内存区段设置特定的信息 移除一个共享内存区段 shmat( ) 挂接一个共享内存区段 shmdt( ) 于一个共享内存区段的分离 同样共享内存的大小也可以用ipcs –lm来查看它的上限下限。我们主要也是关心三个变量,一个是一共可以建立多少个共享内存段,每个段都大可以多少,一共有多少内存可以共享。 使用下面的命令查看共享内存的大小: max number of segments = 4096//总共可以有多少个段 max seg size (kbytes) = 4194303//一个段可以多大 max total shared memory (kbytes) = 1073741824//所有可以共享的内存大小 min seg size (bytes) =1 # cat /proc/sys/kernel/shmmax 修改共享内存大小: 临时修改:在root用户下执行

实验6 进程及进程间的通信之共享内存

实验6 进程及进程间的通信 ●实验目的: 1、理解进程的概念 2、掌握进程复制函数fork的用法 3、掌握替换进程映像exec函数族 4、掌握进程间的通信机制,包括:有名管道、无名管道、信 号、共享内存、信号量和消息队列 ●实验要求: 熟练使用该节所介绍fork函数、exec函数族、以及进程间通信的相关函数。 ●实验器材: 软件: 1.安装了Ubunt的vmware虚拟机 硬件:PC机一台 ●实验步骤: 1、用进程相关API 函数编程一个程序,使之产生一个进程 扇:父进程产生一系列子进程,每个子进程打印自己的PID 然后退出。要求父进程最后打印PID。 进程扇process_fan.c参考代码如下:

2、用进程相关API 函数编写一个程序,使之产生一个进程 链:父进程派生一个子进程后,然后打印出自己的PID,然后退出,该子进程继续派生子进程,然后打印PID,然后退出,以此类推。

要求:1) 实现一个父进程要比子进程先打印PID 的版本。(即 打印的PID 一般是递增的) 2 )实现一个子进程要比父进程先打印PID 的版本。(即打印的PID 一般是递减的) 进程链1,process_chain1.c的参考代码如下:

进程链2,process_chain2.c的参考代码如下:

3、编写程序execl.c,实现父进程打印自己的pid号,子进程调用 execl函数,用可执行程序file_creat替换本进程。注意命令行参数。 参考代码如下: /*execl.c*/ #include #include #include

共享内存使用方法

共享内存---shmget shmat shmdt 要使用共享内存,应该有如下步骤: 1.开辟一块共享内存shmget() 2.允许本进程使用共某块共享内存shmat() 3.写入/读出 4.禁止本进程使用这块共享内存shmdt() 5.删除这块共享内存shmctl()或者命令行下ipcrm ftok()。它有两个参数,一个是字符串,一个是字符。字符串一般用当前进程的程序名,字符一般用来标记这个标识符所标识的共享内存是这个进程所开辟的第几个共享内存。ftok()会返回一个key_t型的值,也就是计算出来的标识符的值。 shmkey = ftok( "mcut" , 'a' ); // 计算标识符 操作共享内存,我们用到了下面的函数 #include #include #include int shmget( key_t shmkey , int shmsiz , int flag ); void *shmat( int shmid , char *shmaddr , int shmflag );

int shmdt( char *shmaddr ); shmget()是用来开辟/指向一块共享内存的函数。参数定义如下:key_t shmkey 是这块共享内存的标识符。如果是父子关系的进程间通信的话,这个标识符用IPC_PRIV A TE来代替。但是刚才我们的两个进程没有任何关系,所以就用ftok()算出来一个标识符使用了。 int shmsiz 是这块内存的大小. int flag 是这块内存的模式(mode)以及权限标识。 模式可取如下值:新建:IPC_CREA T 使用已开辟的内存:IPC_ALLOC 如果标识符以存在,则返回错误值:IPC_EXCL 然后将“模式” 和“权限标识”进行“或”运算,做为第三个参数。 如:IPC_CREA T | IPC_EXCL | 0666 这个函数成功时返回共享内存的ID,失败时返回-1。 // shmid开辟共享内存 shmid = shmget( shmkey , sizeof(in_data) , IPC_CREA T | 0666 ) ; shmat()是用来允许本进程访问一块共享内存的函数。 int shmid是那块共享内存的ID。

内存共享

共享内存函数由shmget、shmat、shmdt、shmctl四个函数组成。下面的表格列出了这四个函数的函数原型及其具体说明。 1. shmget函数原型 shmget(得到一个共享内存标识符或创建一个共享内存对象) 所 需 头文件#include #include 函数说明得到一个共享内存标识符或创建一个共享内存对象并返回共享内存标识符 函 数 原 型 int shmget(key_t key, size_t size, int shmflg) 函数传key 0(IPC_PRIVATE):会建立新共享内存对象 大于0的32位整数:视参数shmflg来确定操作。通常要求 此值来源于ftok返回的IPC键值

入值size 大于0的整数:新建的共享内存大小,以字节为单位 0:只获取共享内存时指定为0 shmflg 0:取共享内存标识符,若不存在则函数会报错 IPC_CREAT:当shmflg&IPC_CREAT为真时,如果内核 中不存在键值与key相等的共享内存,则新建一个共享内 存;如果存在这样的共享内存,返回此共享内存的标识符 IPC_CREAT|IPC_EXCL:如果内核中不存在键值与key相 等的共享内存,则新建一个消息队列;如果存在这样的共享 内存则报错 函数返回值成功:返回共享内存的标识符 出错:-1,错误原因存于error中 附 加说明上述shmflg参数为模式标志参数,使用时需要与IPC对象存取权限(如0600)进行|运算来确定信号量集的存取权限 错误代EINVAL:参数size小于SHMMIN或大于SHMMAX EEXIST:预建立key所指的共享内存,但已经存在

extremeDB使用例子

来一份eXtremeDB使用笔记. 1、准备工作:下载eXtremeDB安装包(https://www.doczj.com/doc/7b12672842.html,/)然后将安装或解压至磁盘。此时可以看到其目录下有host、include、platform和target等目录。 2、用你喜欢的文本编辑器构建一数据库结构,文本内容如下:(举例说明,保存文件名为test.mco) #define int1 signed<1> #define int2 signed<2> #define int4 signed<4> #define int8 signed<8> #define uint8 unsigned<8> #define uint4 unsigned<4> #define uint2 unsigned<2> #define uint1 unsigned<1> // db over shm memory test declare database shmdb; //数据名字 compact class MyClass //表名字 { unsigned<4> id; string str1; char<20> str2; unique tree pkey; //索引 }; 3、用host in目录里的mcocomp.exe程序在DOS命令行模式下将test.mco编译生成,用法如: 》mcocomp test.mco 编译成功后将会生成shmdb.h和shmdb.c文件。当然了,可以根据需要生成所需的文件,具体请见mcocomp命令的参数(mcocomp -help)。至此,生成的文件里就含有数据库操作所需要API函数了。 4、新建一控制台程序工程为shmdb,在链接库里加上mcolib_shm.lib(此处为共享内存LIB库),此处需要注意LIB的路径,最简单的办法就是将eXtremeDB的库文件拷贝至工程目录下包含其就可以了。 5、将编译生成的shmdb.h和shmdb.c添加至此工程中。然后新建一C文件shmdemo.c(当然了,也可以是.cpp文件),下面将分别讲解shmdemo.c文件代码。先看此文件的全部代码: /*标准库*/

共享内存的原理

共享内存 不同进程共享内存示意图 共享内存指在多处理器的计算机系统中,可以被不同中央处理器(CPU)访问的大容量内存。由于多个CPU需要快速访问存储器,这样就要对存储器进行缓存(Cache)。任何一个缓存的数据被更新后,由于其他处理器也可能要存取,共享内存就需要立即更新,否则不同的处理器可能用到不同的数据。共享内存(shared memory)是 Unix下的多进程之间的通信方法 ,这种方法通常用于一个程序的多进程间通信,实际上多个程序间也可以通过共享内存来传递信息。 目录 共享内存的创建 共享内存是存在于内核级别的一种资源,在shell中可以使用ipcs命令来查看当前系统IPC中的状态,在文件系统/proc目录下有对其描述的相应文件。函数shmget可以创建或打开一块共享内存区。函数原型如下:#include int shmget( key_t key, size_t size, int flag );

函数中参数key用来变换成一个标识符,而且每一个IPC对象与一个key相对应。当新建一个共享内存段时,size参数为要请求的内存长度(以字节为单位)。 注意:内核是以页为单位分配内存,当size参数的值不是系统内存页长的整数倍时,系统会分配给进程最小的可以满足size长的页数,但是最后一页的剩余部分内存是不可用的。 当打开一个内存段时,参数size的值为0。参数flag中的相应权限位初始化ipc_perm结构体中的mode域。同时参数flag是函数行为参数,它指定一些当函数遇到阻塞或其他情况时应做出的反应。shmid_ds结构初始化如表14-4所示。 初始化

信号量和共享内存

信号量(semaphore)Kless0329 (实现同步) 一种是系统调用,一种是调用linux库函数 信号量实现同步: A B两个程序打印AA B B 使每一次都连着打印A或B 只需一对信号量val= 1 A(p(0),v(0)) B(p(0),v(0)) p(0):是对val值为0的信号量进行p操作 AB两个程序进行读写同步,A写一个,B读一个,需要两对信号量(val= 1和val = 0,A( p(1),v(0) ) B( p(0),v(1) ) ) 一、系统调用(2) 1、创建信号量(semget),成功后设置信号量的值(semctl) == 另一个进程获取信号量 2、进行pv操作(semop) //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 通过key获取semid pv 操作就是对senbuf 里面的内容进行改动sem_num 只有一个,所以下标就是0 删除时是删除信号量集 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 3、删除信号量(semctl) 注意:删除操作必须在pv操作结束后进行(与共享内存对比) 只需删除一次,不论在哪个进程中删除都可以 1、创建

共享内存C++

CreateFileMapping函数 CreateFileMapping函数:创建或者打开一个指定内存中已命名或者未命名的文件映射对象 HANDLE WINAPI CreateFileMapping( _in HANDLE hFile, _in_opt LPSECURITY_ATTRIBUTES lpAttributes, _in DWORD flProtect, _in DWORD dwMaximumSizeHigh, _in DWORD dwMaximumSizeLow, _in_opt LPCTSTR lpName ); 参数说明: hFile[in] 句柄文件,从该句柄中创建一个文件映射对象。 打开该文件时必须获得访问权限,访问权限由保护标志参数flProtect来设置。 如果hFile参数值为INV ALID_HANDLE_V ALUE的话,还得在dwMaximumSizeHigh参数和dwMaximumSizeLow参数中指定映射文件对象的大小。在这种情况下创建的是一个指定大小的文件映射对象,创建的文件映射对象在系统的分页文件中,而不是文件系统中的文件。 lpAttribute[in,option] 一个指向SECURITY_ATTRIBUTES结构体的指针,该指针指定返回的句柄是否可以被子进程继承。在SECURITY_ATTRIBUTES结构体中的lpSecurityDescriptor成员作为新的文件映射对象的安全描述符。 如果lpAttribute为NULL,返回句柄不能被子进程继承,文件映射对象获取默认的安全描述符。文件映射对象中默认安全描述符的访问控制列表时来自于生成器中的主令牌或者模拟令牌。 flProtect [in] 指定文件映射对象的页保护标志。所有对象的映射视图必须与该保护位兼容。

分布式共享内存

第7章分布式共享内存 在本章中,我们研究实现分布式共享内存(distributed shared memory简称DSM)。 7.1引论 传统上,分布式计算是基于消息传递模型,在这种模型下进程们经由以消息形式交换数据来彼此互相交互和共享数据。Hoare的通讯顺序进程(communicating sequential processes),客户-服务器模型和远程过程调用都是这种模型的例子。 分布式共享内存(Distributed shared memory简称DSM)系统是分布式操作系统的一个资源管理成分,它实现在没有物理地共享内存的分布式系统中的共享内存模型。见图7.1。 图7.1分布式系统中的共享内存模型 这个共享内存模型提供一个虚拟地址空间,使得被在一个分布式系统中所有结点(计算机)之间共享。 7.2体系结构和动力 具有分布式共享内存,程序访问在共享地址空间中的数据正如同访问在传统的虚存中的数据一样。在支持分布式共享内存的系统中,数据既在辅存和主存之间也在不同结点的主存之间移动。 每个结点可以拥有存贮在共享地址空间中的数据,并且当数据从一个结点移到另一个结点时,拥有关系可以改变。当一个进程访问在共享地址空间中的数据时,一个映照管理者(mapping manager) 映照共享内存地址到物理存储,这个物理存储可以是本地或远程的。 映照管理者是一个或者实现在操作系统内核中或者作为一个运行时库例程的软件层。 为了减少由于通讯误而带来的延迟,当共享内存地址映照到在在一个远程结点上的一个物理内存位置时,分布式共享内存可以移动在共享内存地址中的数据从一个远程结点到正在访问数据的结点。在这样情况下,分布式共享内存利用底层通讯系统的通讯服务。

共享内存和信号量

实验7 共享内存和信号量(进程间通信) 邢卫2008-11-26修订 实验目的 学习并掌握Linux系统中的进程间通信机制,包括共享内存和信号量。 实验内容 1.学习共享内存相关的系统调用 shmget(), shmat(), shmdt, shmctl() 2.学习信号量(semaphore)相关的系统调用 semget(), semop(), semctl() 3.学习信号(signal)相关的系统调用 signal(), atexit()等 4.完成《边干边学》第6.4.1节的实验程序的编辑、编译、运行操作 5.分析、学习实验程序的工作过程和原理 6.选做:学习《边干边学》第6章,结合使用联机手册(可以从man 2 ipc命令开 始),编程练习各种进程间通信机制 实验步骤 1.以stu帐号登录 2.编辑reader_writer1.c程序 注意:在193页delete()函数中,注意改成 if (mysemctl(Semid, 0, IPC_RMID, (union semun)0) == -1) { 3.编译gcc reader_writer1.c -o reader_writer1 4.运行./reader_writer1 注意记录下共享内存的id号 5.使用Alt+F2切换到第2个登录窗口,再次以stu帐号登录 可以使用who命令查看验证此时有两个stu用户已登录 可以使用ps –l命令查看这两个stu用户的进程 6.在第2个stu用户窗口中,输入./reader_writer1共享内存的id号注意:此时,第2个stu用户窗口中的进程担当writer角色,第1个stu用户窗口 中的进程担当reader角色。

Windows进程之间共享内存

Windows2000中进程之间共享内存的几个主要应用是,一个dll(动态链接库)可能被多个进程使用,应该被共享。一个程序也应该可以被多个运行的实例共 享。通过文件映射(Memory Mapped File)实现的进程之间通过内存通信,传输数据。 每个进程有自己的4G地址空间,地址空间通过进程自己的页目录和页表,以页为单位映射物理内存。把两个不同进程的一页地址空间映射到同一个物理页上 ,两个进程的一页地址空间就实现了共享,两个进程对该页地址空间的读写,都是对同一个物理页的读写。两个进程自己的某个PTE(页表项,对应一页地址空 间)中的物理页帧号相同,就使两个进程的某页映射到了同一个物理页。比如进程1的0x10000-0x10FFF这一页映射物理内存的第100页,进程2的0x20000- 0x20FFF这一页也映射物理内存的第100页,那么进程1的0x10000-0x10FFF的就是进程2的0x20000-0x20FFF,就是物理内存的第100页。 Prototype PTE(原型PTE) 和共享的实现有着密切关系的一个数据结构是页帧号数据库项(PFN DataBase Entry),对处于Active(Valid)状态的物理页,该物理页的PFN DataBase Entry的+08处,4个字节,是share count,共享计数。 下面我们分析一下进程间共享物理页的几种情况。 进程1第一次将一些可以被共享的内容读入一个物理页。于是进程1相应的PTE有效,并指向这个物理页。被共享的物理页对应的PFN DataBase Entry状态为 Active(Valid),share count值为1。 进程2需要共享这个物理页,于是进程2相应的PTE有效,并指向这个物理页。由于这个物理页现在被进程1和进程2共享,所以对应的PFN DataBase Entry的 share count的值加1,变为2。 进程3需要共享这个物理页,于是进程3相应的PTE有效,并指向这个物理页。这个物理页对应的PFN DataBase Entry的share count的值加1,变为3。 进程2修整Working Set(工作集),决定把该页从自己的Working Set中移出,于是相应的PTE无效。这个物理页对应的PFN DataBase Entry的share count的值减1,变为2。 进程1结束,这个物理页对应的PFN DataBase Entry的share count的值又减1,变为1。进程2又需要访问这个共享页。于是PTE重新有效,并指向这个物理页。物理页的share count加1,又变为2。 进程2,进程3,修整Working Set(工作集),都把这页从Working Set中移出,于是两个进程相应的PTE都无效。物理页的share count从2变成了0。当 变成0时,该物理页的状态从Active(Valid)变成了Standby,链入了Standby链,不过该物理页中的内容不会被改变。 进程2又需要访问这个共享页。由于该物理页在Standby链上,内容没有被改变。于是直接取回该物理页,PTE重新有效并指向这个物理页。物理页状态从 Standby变为Active(Valid),share count变为1。 进程2又修整Working Set(工作集),决定把该页从自己的Working Set中移出,于是相应的PTE无效。这个物理页的share count的值减1,变为0。当变 成0时,该物理页的状态从Active(Valid)变成了Standby,链入了Standby链,不过该物理页中的内容不会被改变。 系统需要内存,从Standby链上取走了该物理页。 进程2又需要访问这个共享页。没有物理页有原来的数据了,于是分配一个新的物理页,从

共享内存使用需要注意的问题

简介 共享内存是一种非常重要且常用的进程间通信方式,相对于其它IPC机制,因其速度最快、效率最高,被广泛应用于各类软件产品及应用开发中。System V IPC 为Unix平台上的共享内存应用制定了统一的API标准,从而为在UNIX/Linux平台上进行跨平台开发提供了极大的便利;开发人员基于一套基本相同的源代码,便可开发出同时支持AIX、Solaris、HP-UX、Linux等平台的产品。 然而,各个平台对System V 标准的API在实现上各有差异,由此对相关应用开发带来影响,甚至引入难以调试的问题。本文将结合作者在Tivoli产品开发中的实际经验,对这些平台相关的问题,以及具有共性的问题,逐一进行分析,并提出解决方法。 1. System V共享内存概述 System V 进程间通信(IPC)包括3种机制:消息队列、信号量、共享内存。消息队列和信号量均是内核空间的系统对象,经由它们的数据需要在内核和用户空间进行额外的数据拷贝;而共享内存和访问它的所有应用程序均同处于用户空间,应用进程可以通过地址映射的方式直接读写内存,从而获得非常高的通信效率。 System V 为共享内存定义了下列API接口函数:

# include # include # include key_t ftok(const char *pathname, int proj_id); int shmget(key_t key, int size, int shmflg); void* shmat(int shmid, const void *shmaddr, int shmflg); int shmdt(void *shmaddr); int shmctl(int shmid, int cmd, struct shmid_ds *buf); ftok 函数用于生成一个键值:key_t key,该键值将作为共享内存对象的唯一性标识符,并提供给为shmget函数作为其输入参数;ftok 函数的输入参数包括一个文件(或目录)路径名:pathname,以及一个额外的数字:proj_id,其中pathname 所指定的文件(或目录)要求必须已经存在,且proj_id不 可为0; shmget 函数用于创建(或者获取)一个由key键值指定的共享内存对象,返回该对象的系统标识符:shmid; shmat 函数用于建立调用进程与由标识符shmid指定的共享内存对 象之间的连接; shmdt 函数用于断开调用进程与共享内存对象之间的连接;shmctl 函数用于对已创建的共享内存对象进行查询、设值、删除等 操作; 2. ftok的陷阱

数据库基础题目示例

基础题目示例 一、选择题 1.下列是SQL语句的类型,哪一种表示的是查询数据?(C) A. UPDATE B. INSERT C. SELECT D. CREATE 2.下列是SQL语句的类型,哪一种表示的是更新数据?(A) A. UPDATE B. INSERT C. SELECT D. CREATE 3.下列是SQL语句的类型,哪一种表示的是插入数据?(B) A. UPDATE B. INSERT C. SELECT D. CREATE 4.下列是SQL语句的类型,哪一种表示的是创建数据结构?(D) A. UPDATE B. INSERT C. SELECT D. CREATE 5.下列是SQL语句的类型,哪一种表示的是删除数据?(D) A. UPDATE B. INSERT C. SELECT D. DELETE 6.假定有一个用户表,表中包含字段:userid (int)、username (varchar)、password(varchar)、等,该表需要设置主键,以下说法正确的是(ab)。(选择两项) a)如果不能有同时重复的username和password,那么username和password可以组合在一起作为主键。 b)此表设计主键时,根据选择主键的最小性原则,最好采用userid 作为主键。 c)此表设计主键时,根据选择主键的最小性原则,最好采用username 和password作为组合键。 d) 如果采用userid作为主键,那么在userid列输入的数值,允许为

空。 7.做为一个DBA,当你要给一个新建的用户授予连接数据库的权限时,你会先用哪个用户登录数据库?(A) A. SYS B. HR C. SCOTT D. SH 8.下面哪两个是普通用户必须要分配的权限?(B) A. SYSDBA B. CONNECT C. RESOURCE D. SYSOPER 9.正常启动数据库的命令是哪一个?(A) A. STARTUP B. ALTER DATABASE OPEN C. STARTUP NOMOUNT D. STARTUP MOUNT 10.日常关闭数据库时用哪一个命令?(D) A.SHUTDOWN ABORT B.SHUTDOWN C.SHUTDOWN TRANSACTIONAL D.SHUTDOWN IMMEDIATE 11.以下(D)语句从表TABLE_NAME中提取前10条记录。(选择一项) a)select * from TABLE_NAME where rowcount=10 b)select TOP 10 * from TABLE_NAME c)select TOP of 10 * from TABLE_NAME d)select * from TABLE_NAME where rownum<=10 12.从“产品”表里查询出价格高于产品名称为“一次性纸杯”的产

共享内存在Java中的实现和应用

共享内存在Java中的实现和应用 在java语言中,基本上没有提及共享内存这个概念,但是,在某一些应用中,共享内 存确实非常有用,例如采用java语言的分布式应用系统中,存在着大量的分布式共享对象, 很多时候需要查询这些对象的状态,以查看系统是否运行正常或者了解这些对象的目前的一 些统计数据和状态。如果采用网络通信的方式,显然会增加应用的额外负担,也增加了一些 不必要的应用编程。而如果采用共享内存的方式,则可以直接通过共享内存查看对象的状态 数据和统计数据,从而减少了一些不必要的麻烦。 共享内存对应应用开发的意义 对熟知UNIX系统应用开发的程序员来说,IPC(InterProcess Communication)机制是非常熟悉的,IPC基本包括共享内存、信号灯操作、消息队列、信号处理等部分,是开发应用中非常重要的必不可少的工具。其中共享内存IPC机制的关键,对于数据共享、系统快速查询、动态配置、减少资源耗费等均有独到的优点。 对应UNIX系统来说,共享内存分为一般共享内存和映像文件共享内存两种,而对应 Windows,实际上只有映像文件共享内存一种。所以java应用中也是只能创建映像文件共享内存。 在java语言中,基本上没有提及共享内存这个概念,但是,在某一些应用中,共享内存确实非常有用,例如采用java语言的分布式应用系统中,存在着大量的分布式共享对象,很多时候需要查询这些对象的状态,以查看系统是否运行正常或者了解这些对象的目前的一些统计数据和状态。如果采用网络通信的方式,显然会增加应用的额外负担,也增加了一些不必要的应用编程。而如果采用共享内存的方式,则可以直接通过共享内存查看对象的状态数据和统计数据,从而减少了一些不必要的麻烦。 共享内存的使用有如下几个特点: 可以被多个进程打开访问; 读写操作的进程在执行读写操作时其他进程不能进行写操作; 多个进程可以交替对某一共享内存执行写操作; 一个进程执行了内存的写操作后,不影响其他进程对该内存的访问。同时其他进程对更新后的内存具有可见性。 在进程执行写操作时如果异常退出,对其他进程写操作禁止应自动解除。 相对共享文件,数据访问的方便性和效率有 另外,共享内存的使用上有如下情况:

共享内存实现进程间大数据的交换

共享内存实现进程间大数据的交换 引言 进程间的数据交换和共享是一种非常重要和实用的技术。大、中型软件的开发设计多是由众多程序设计人员的合作完成,通常一个程序设计人员只负责其中一个或几个模块的开发,这些模块可以是动态链接库也可以是应用程序或是其他形式的程序组件。这些独立开发出来的程序模块最终需要作为一个整体来运行,即组成一个系统,在系统运行期间这些模块往往需要频繁地进行数据交换和数据共享,对于动态链接库同其主调应用程序之间的数据交换是非常容易实现的,但是在两个应用程序之间或是动态链接库同其主调应用程序之外的其他应用程序进行数据交换就比较困难了。尤其是在交换数据量过大、交换过于频繁的情况下更是难以实现,本文即对此展开讨论,并提出了一种通过共享内存来实现进程见大数据量快速交换的一种方法。 通讯方式的比较和选择 进程间通讯的方式有很多,常用的有共享内存、命名管道和匿名管道、发送消息等几种方法来直接完成,另外还可以通过socket口、配置文件和注册表等来间接实现进程间数据通讯任务。以上这几种方法各有优缺点,具体到在进程间进行大数据量数据的快速交换问题上,则可以排除使用配置文件和注册表的方法;另外,由于管道和socket套接字的使用需要有网卡的支持,因此也可以不予考虑。这样,可供选择的通讯方式只剩下共享内存和发送消息两种。由于数据量比较大,这样在使用消息进行通讯时就无法通过消息参数将数据直接携带到接收方,只能以地址传送的方式进行。当一个应用程序向另一个应用程序发送数据时将会发出WM_COPYDATA系统消息,因此可以考虑通过向消息队列插入 WM_COPYDATA消息的方法来实现数据在进程间的拷贝。 在使用WM_COPYDATA消息时,由第一个消息参数指定发送窗口的句柄,第二个消息参数则为一同数据相关的数据结构COPYDATASTRUCT的指针,此结构原形声明如下: typedef struct tagCOPYDATASTRUCT { DWORD dwData; DWORD cbData; PVOID lpData; } COPYDATASTRUCT; 其中,只需将待发送数据的首地址赋予lpData、并由cbData指明数据块长度即可。消息发出后,接收方程序在 WM_COPYDATA消息的响应函数中通过随消息传递进来的第二个参数完成对数据块的接收。但是在使用WM_COPYDATA消息时,只能用SendMessage()函数发送而不能使用PostMessage(),这两个函数虽然功能非常相似都是负责向指定的窗口发送消息,但是SendMessage()函数发出消息后不是马上返回,而是在接收方的消息响应函数处理完之后才能返回,并能够得到返回结果。在此期间发送方程序将被阻塞,SendMessage()后面的语句不能被继续执行。而PostMessage()函数在发出消息后马上返回,其后语句能够被立即执行,但是无法获取消息的执行结果。可见,在交换数据量较大的情况下实现数据频繁而又快速的交换用发送WM_COPYDATA消息的方法也是不合适的,当数据传输过于频繁时将有可能导致数据的丢失。 比之以上几种进程间通讯方法,共享内存有着明显的优势。共享内存是通过直接操作内存映射文件来进行的,而内存映射文件又是进行单机数据共享的最低层机制,前面几种数据交换方式在低层都是通过内存映射文件来进行的。因此使用共享内存可以以较小的开销获取较高的性能,是进行大数据量数据快速交换的最佳方案。 共享内存的使用 在Windows操作系统下,任何一个进程不允许读取、写入或是修改另一个进程的数据(包括变量、对象和内存分配等),但是在某个进程内创建的文件映射对象的视图却能够为多个其他进程所映射,这些进程共享的是物理存储器的同一个页面。因此,当一个进程将数据写入此共享文件映射对象的视图时,其他进程可以立即获取数据变更情况。为了进一步提高数据交换的速度,还可以采用由系统页文件支持的内存映射文件而直接在内存区域使用,显然这种共享内存的方式是完全可以满足在进程间进行大数据量数据快速传输任务要求的。下面给出在两个相互独立的进程间通过文件映射对象来分配和访问同一个共享内存块的应用实例。在本例中,由发送方程序负责向接收方程序发送数据,文件映射对象由发送方创建和关闭,并且指定一个唯一的名字供接收程序使用。接收方程序直接通过这个唯一指定的名字打开此文件映射对象,并完成对数据的接收。 在发送方程序中,首先通过CreateFileMapping()函数创建一个内存映射文件对象,如果创建成功则通过MapViewOfFile()函数将此文件映射对象的视图映射进地址空间,同时得到此映射视图的首址。可见,共享内存的创建主要是通过这两个函数完成的。这两个函数原形声明如下: HANDLE CreateFileMapping(HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCTSTR lpName); LPVOID MapViewOfFile(HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, DWORD dwNumberOfBytesToMap); CreateFileMapping()函数参数hFile指定了待映射到进程地址空间的文件句柄,如果为无效句柄则系统会创建一个使用来自页文件而非指定磁盘文件存储器的文件映射对象。很显然,在本例中为了数据能快速交换,需要人为将此参数设定为INVALID_HANDLE_VALUE;参数flProtect设定了系统对页面采取的保护属性,由于需要进行读写操作,因此可以设置保护属性PAGE_READWRITE;双字型参数dwMaximumSizeHigh和dwMaximumSizeLow指定了所开辟共享内存区的最大字节数;最后的参数lpName用来给此共享内存设定一个名字,接收程序可以通过这个名字将其打开。MapViewOfFile()函数的

共享内存实例及文件映射编程及实现原理

目录 (一)IPC共享内存和文件映射的区别 1 (二)共享内存实现流程总结 1 (三)存储映射I/O(包含实现原理说明) 2 文件映射API补充 4 (四)IPC共享存储(包含实现原理说明) 6 (五)共享内存实现基本原理10 (六)IPC共享内存实现机制11 (七)文件映射的实现机制13 (一)IPC共享内存和文件映射的区别 1. 文件映射的页框是磁盘文件高速缓存中的页框,内核线程pdflush会将页框中的内容回写进磁盘,如果是私有映射类型,将会进行写时复制。而IPC共享内存映射的是一种特殊文件系统中的文件高速缓存,它没有相应的磁盘映像。 2. IPC共享内存只存在于内存中,系统重新启动,数据将会丢失。而文件共享映射会将数据写回磁盘。 3. IPC共享内存的大小是在创建的时候指定,而且大小不能改变,而文件在创建时大小为0,此时还不能建立映射,文件的大小会间接的决定映射区的大小。例如文件的大小是123,而要求映射的区域大小是4096*2,但实际只会分配4096的映射空间,此时引用4096以后的线性空间将引起缺页异常。 4. 当第一次读取共享内存时IPC共享内存对象将分配一个新的页框,而文件映射分配新页框的同时会将磁盘中的数据写入新页框。 5. IPC共享内存不需要写回磁盘操作,完全是为共享内存而设计,所以使用效率会更高。 6. IPC共享内存对象必须调用shmctl()显示的撤销,否则会一直保留着,使用key或者id号定位一个共享内存对象,key和id号的对应关系并不是固定的。例如,第一次使用key建立一个共享内存对象为shm1对应的id为id1,之后系统重新启动,然后再使用key 建立一个共享内存对象shm2,对应的id是id2,此时id2和id1是不同的。而文件映射使用相同的路径将会定位相同的磁盘文件。 总结:IPC共享内存和文件映射的实现机制是一样的,文件映射的目的是加快对文件的读写速度,而IPC共享内存就是为了共享内存而设计的,所以效率会高一些。 (二)共享内存实现流程总结 1. 建立一个线性区对象struct vm_area_struct 并加入进程的内存描述符current->mm中。 函数mmap()和shmat()就是用于建立并注册线性区对象,这个对象中的struct file *vm_file指向映射文件的文件对象,vm_page_prot是线性区中页框的访问许可权。但此时并未修改进程的页表,而是注册相应的缺页异常回调函数,注册在对象的vm_ops。 2. 当进程第一次访问共享内存区时,由于相应的页表还未填写,将产生缺页异常,并根据线性地址找到对应的线性区对象,然后调用前边注册过的缺页异常回调函数,并根据vm_file文件对象和vm_page_prot的信息来填写相应的页表项,最后重新执行产生缺页异常的代码。 说明:文件映射和IPC共享内存映射的物理页框都是磁盘文件的页高速缓存中的,IPC 共享内存使用一种特殊文件系统,这个文件系统并没有对应的磁盘映像,只是复用了文件系统的框架。更详细的内容参见后边的五,六,七节。 下面3,4节是《UNIX环境高级编程》对文件映射和IPC共享内存的讲解,已经说明的很详细了,我在它的基础上附加了一些内核实现原理的说明,实现原理说明部分放在括号内。 (三)存储映射I/O(包含实现原理说明) 存储映射I/O使一个磁盘文件与存储空间中的一个缓存相映射。于是当从缓存中取数据,就相当于读文件中的相应字节。与其类似,将数据存入缓存,则相应字节就自动地写入文件。这样,就可以在不使用read和write的情况下执行I/O。

相关主题
文本预览
相关文档 最新文档