当前位置:首页 » 电脑资讯 » 共享内存为什么创建文件

共享内存为什么创建文件

发布时间: 2022-05-10 07:12:20

1. windows 共享内存有几种方式

  1. 使用shared类型的section,可以让变量在同一个可执行文件(image)创建的多个进程间共享;

  2. 使用动态链接库(DLL),可以让变量在不同image创建的进程间共享

  3. 使用FileMapping,可以在不同进程间共享一段内存

2. 怎么利用设计模式来更有效的使用共享内存

IOCTL 方法:应用程序分配共享内存

在用户模式与核心模式之间共享内存的最简单有效的方法是使用 IOCTL。IOCTL 有四种不同的类型,下列三种 IOCTL 使您可以在设备驱动程序中直接访问用户缓冲区:

METHOD_IN_DIRECT
METHOD_OUT_DIRECT
METHOD_NEITHER
在以上这些方法中没有创建中间系统缓冲区。

METHOD_IN_DIRECT 和 METHOD_OUT_DIRECT 自动在 DeviceIoControl 中锁定用户指定的缓冲区,并为驱动程序创建内存描述列表 (MDL)。驱动程序可以从 MDL 得到一个系统地址,并根据 IOCTL 传输类型将信息传入传出缓冲区。由于所有的缓冲区验证、锁定及 MDL 创建均是通过 I/O 管理器来完成的,所以这是一种简单的方法。

相反,METHOD_NEITHER 直接将用户缓冲区提供给驱动程序,驱动程序必须适当地验证缓冲区并锁定缓冲区,如果需要,还要为缓冲区获取一个系统地址。虽然这是通过设备驱动程序 I/O 子系统的最快捷路径,但使用这种方法时也有一些应当注意的问题。有关其它信息,请参见 Microsoft Knowledge Base 中的下列文章:

Q126416 INFO:使用 METHOD_NEITHER IOCTL 的警告
要了解这三种不同的 IOCTL 如何工作,请参见以下 Microsoft Knowledge Base 文章:

Q178317 文件:IOCTL.exe:如何使用不同类型的 IOCTL
MmMapLockedPages 方法:设备驱动程序分配共享内存

在这种方法中,驱动程序通过 MmAllocateContiguousMemory 或 ExAllocatePoolXxx 函数分配内存,创建并建立描述缓冲区的 MDL,并使用 MmMapLockedPages 把内存映射到用户进程地址空间中。用户应用程序可以使用由 MmMapLockPages 返回的虚拟地址直接访问系统内存。

由于应当在访问内存的进程上下文中完成映射,所以此方法只能用于单层结构的驱动程序,这时可以保证 dispatch 例程在调用进程上下文中运行。您可以在任意数量的用户过程地址空间上映射同一个系统缓冲区。不过,应当设计一种保护机制,使驱动程序及所有应用程序对内存的访问同步。进一步说,应当在终止进程之前或者一旦使用完缓冲区就在映射缓冲区的相同进程上下文中取消缓冲区的映射。下面介绍将驱动程序缓冲区映射至某个用户进程时需采取的步骤:

首先如下分配内存:

SystemVirtualAddress = MmAllocateContiguousMemory(NumberOfBytes,
HighestAcceptableAddress); 或
SystemVirtualAddress = ExAllocatePool(PoolType, NumberOfBytes);

如下分配一个 MDL:

Mdl = IoAllocateMdl(SystemVirtualAddress, NumberOfBytes, FALSE,
FALSE, NULL);

建立 MDL 以描述内存页。如果已经分配了非页面缓冲池中的内存,请使用:

MmBuildMdlForNonPagedPool(Mdl);
如果分配了页面缓冲池中的内存,请使用:

MmProbeAndLockPages(Mdl, KernelMode, IoWriteAccess);
如下将锁定的页面映射至进程的用户地址空间中:

UserVirtualAddress = MmMapLockedPages(Mdl, UserMode);

前三步可以在 DriverEntry 或 Dispatch 例程中完成。但是,将缓冲区映射至用户地址空间的最后一步,应当在运行于调用进程上下文的某个例程(通常是单层驱动程序的 dispatch 例程)中完成。

您可以在某个提高的 IRQL 级及任何进程上下文(即中断服务例程 (ISR) 及延迟过程调用 (DPC))的驱动程序中使用 SystemVirtualAddress,在应用程序或运行正确进程上下文的驱动程序中使用 UserVirtualAddress。

按照下列步骤取消映射并释放缓冲区:
首先从用户地址空间中取消页面映射。应在映射 UserVirtualAddress 的进程上下文中运行时调用函数:
MmUnmapLockedPages(UserVirtualAddress, Mdl);
如果使用 MmProbleAndLockPages 锁定了页面,则使用以下函数解锁:
MmUnlockPages(Mdl)
释放 MDL:
IoFreeMdl(Mdl);
释放系统内存:
MmFreeContiguousMemory(SystemVirtualAddress); 或
ExFreePool(SystemVirtualAddress);
共享内存对象方法

使用保存在页面文件上的内存映射文件是用于在用户进程之间共享内存的常用方法。不过,您可以使用以上技术在用户过程及设备驱动程序之间共享内存。使用这种技术有两种方法。在第一种方法中,驱动程序可以创建命名内存对象(称为 section 对象),一个或多个应用程序通过使用 OpenFileMapping 打开以上对象,然后调用 MapViewOfFile 函数来得到指向它的指针。通过指定以上对象的保护属性,可以定义某个进程使用内存的方式。

在第二种方法中,应用程序可以使用 CreateFileMapping 在用户模式下创建一个命名内存对象。驱动程序通过使用 ZwMapViewOfSection 函数及调用 ZwMapViewOfSection 得到其指针来打开以上内存对象。您应当使用异常处理程序在核心模式中访问该内存地址。有关使用这种技术的范例,请参见下列 Microsoft Knowledge Base 文章:

Q194945 样例:有关在核心和用户模式之间共享内存的 Section.exe
因为总是在进程的用户地址空间(小于 0x80000000,不管是在核心模式还是在用户模式中创建对象)上映射对象,所以只在进程上下文中访问地址时地址才有效。在相同内存对象上对 MapViewOfFile 或 ZwMapViewOfSection 的每次调用将返回一个不同的内存地址,即使对于相同的进程也是如此。通常不建议使用这种方法,特别是对于低级设备驱动程序而言。如前所述,这是因为地址范围被限制于映射对象的进程中,不能在 DPC 或 ISR 中访问。而且,在核心模式中创建内存对象的 API 没有记载于 DDK 中。

然而,要在提高的 IRQL (如 DPC 或 ISR)上使用该地址,您一定要查明并锁定缓冲区页面,并得到如 IOCTL 方法中所述的系统虚拟地址 (MmGetSystemAddressForMdl)。

只有准备在两个(或多个)用户进程和一个(或多个)设备驱动程序之间共享内存时,这种方法才比较简单容易。否则,使用 IOCTL 技术在一个用户过程及一个设备驱动程序之间共享内存将更为简单有效。

3. 关于IPC$

程间通信就是在不同进程之间传播或交换信息,那么不同进程之间存在着什么双方都可以访问的介质呢?进程的用户空间是互相独立的,一般而言是不能互相访问的,唯一的例外是共享内存区。但是,系统空间却是“公共场所”,所以内核显然可以提供这样的条件。除此以外,那就是双方都可以访问的外设了。在这个意义上,两个进程当然也可以通过磁盘上的普通文件交换信息,或者通过“注册表”或其它数据库中的某些表项和记录交换信息。广义上这也是进程间通信的手段,但是一般都不把这算作“进程间通信”。因为那些通信手段的效率太低了,而人们对进程间通信的要求是要有一定的实时性。
进程间通信主要包括管道, 系统IPC(包括消息队列,信号量,共享存储), SOCKET.
管道包括三种:1)普通管道PIPE, 通常有种限制,一是半双工,只能单向传输;二是只能在父子进程间使用. 2)流管道s_pipe: 去除了第一种限制,可以双向传输. 3)命名管道:name_pipe, 去除了第二种限制,可以在许多并不相关的进程之间进行通讯.
系统IPC的三种方式类同,都是使用了内核里的标识符来识别.
FAQ1: 管道与文件描述符,文件指针的关系?
答: 其实管道的使用方法与文件类似,都能使用read,write,open等普通IO函数. 管道描述符来类似于文件描述符. 事实上, 管道使用的描述符, 文件指针和文件描述符最终都会转化成系统中SOCKET描述符. 都受到系统内核中SOCKET描述符的限制. 本质上LINUX内核源码中管道是通过空文件来实现.
FAQ2: 管道的使用方法?
答: 主要有下面几种方法: 1)pipe, 创建一个管道,返回2个管道描述符.通常用于父子进程之间通讯. 2)popen, pclose: 这种方式只返回一个管道描述符,常用于通信另一方是stdin or stdout; 3)mkpipe: 命名管道, 在许多进程之间进行交互.
FAQ3: 管道与系统IPC之间的优劣比较?
答: 管道: 优点是所有的UNIX实现都支持, 并且在最后一个访问管道的进程终止后,管道就被完全删除;缺陷是管道只允许单向传输或者用于父子进程之间.
系统IPC: 优点是功能强大,能在毫不相关进程之间进行通讯; 缺陷是关键字KEY_T使用了内核标识,占用了内核资源,而且只能被显式删除,而且不能使用SOCKET的一些机制,例如select,epoll等.
FAQ4: WINDOS进程间通信与LINUX进程间通信的关系?
答: 事实上,WINDOS的进程通信大部分移植于UNIX, WINDOS的剪贴板,文件映射等都可从UNIX进程通信的共享存储中找到影子.
FAQ5: 进程间通信与线程间通信之间的关系?
答: 因为WINDOWS运行的实体是线程, 狭义上的进程间通信其实是指分属于不同进程的线程之间的通讯.而单个进程之间的线程同步问题可归并为一种特殊的进程通信.它要用到内核支持的系统调用来保持线程之间同步. 通常用到的一些线程同步方法包括:Event, Mutex, 信号量Semaphore, 临界区资源等.
Linux的进程间通信(IPC,InterProcess Communication)通信方法有管道、消息队列、信号量、共享内存、套接口等。
管道分为有名管道和无名管道,无名管道只能用于亲属进程之间的通信,而有名管道则可用于无亲属关系的进程之间。
#define INPUT 0
#define OUTPUT 1
void main()
{
int file_descriptors[2];
/*定义子进程号 */
pid_t pid;
char buf[BUFFER_LEN];
int returned_count;
/*创建无名管道*/
pipe(file_descriptors);
/*创建子进程*/
if ((pid = fork()) == - 1)
{
printf("Error in fork\n");
exit(1);
}
/*执行子进程*/
if (pid == 0)
{
printf("in the spawned (child) process...\n");
/*子进程向父进程写数据,关闭管道的读端*/
close(file_descriptors[INPUT]);
write(file_descriptors[OUTPUT], "test data", strlen("test data"));
exit(0);
}
else
{
/*执行父进程*/
printf("in the spawning (parent) process...\n");
/*父进程从管道读取子进程写的数据,关闭管道的写端*/
close(file_descriptors[OUTPUT]);
returned_count = read(file_descriptors[INPUT], buf, sizeof(buf));
printf("%d bytes of data received from spawned process: %s\n",
returned_count, buf);
}
}
上述程序中,无名管道以int pipe(int filedis[2]);方式定义,参数filedis返回两个文件描述符filedes[0]为读而打开,filedes[1]为写而打开,filedes[1]的输出是filedes[0]的输入;
在Linux系统下,有名管道可由两种方式创建(假设创建一个名为“fifoexample”的有名管道):
(1)mkfifo("fifoexample","rw");
(2)mknod fifoexample p
mkfifo是一个函数,mknod是一个系统调用,即我们可以在shell下输出上述命令。
有名管道创建后,我们可以像读写文件一样读写之:
/* 进程一:读有名管道*/
void main()
{
FILE *in_file;
int count = 1;
char buf[BUFFER_LEN];
in_file = fopen("pipeexample", "r");
if (in_file == NULL)
{
printf("Error in fdopen.\n");
exit(1);
}
while ((count = fread(buf, 1, BUFFER_LEN, in_file)) > 0)
printf("received from pipe: %s\n", buf);
fclose(in_file);
}
/* 进程二:写有名管道*/
void main()
{
FILE *out_file;
int count = 1;
char buf[BUFFER_LEN];
out_file = fopen("pipeexample", "w");
if (out_file == NULL)
{
printf("Error opening pipe.");
exit(1);
}
sprintf(buf, "this is test data for the named pipe example\n");
fwrite(buf, 1, BUFFER_LEN, out_file);
fclose(out_file);
}
消息队列用于运行于同一台机器上的进程间通信,与管道相似;
共享内存通常由一个进程创建,其余进程对这块内存区进行读写。得到共享内存有两种方式:映射/dev/mem设备和内存映像文件。前一种方式不给系统带来额外的开销,但在现实中并不常用,因为它控制存取的是实际的物理内存;常用的方式是通过shmXXX函数族来实现共享内存:
int shmget(key_t key, int size, int flag); /* 获得一个共享存储标识符 */
该函数使得系统分配size大小的内存用作共享内存;
void *shmat(int shmid, void *addr, int flag); /* 将共享内存连接到自身地址空间中*/
shmid为shmget函数返回的共享存储标识符,addr和flag参数决定了以什么方式来确定连接的地址,函数的返回值即是该进程数据段所连接的实际地址。此后,进程可以对此地址进行读写操作访问共享内存。
本质上,信号量是一个计数器,它用来记录对某个资源(如共享内存)的存取状况。一般说来,为了获得共享资源,进程需要执行下列操作:
(1)测试控制该资源的信号量;
(2)若此信号量的值为正,则允许进行使用该资源,进程将进号量减1;
(3)若此信号量为0,则该资源目前不可用,进程进入睡眠状态,直至信号量值大于0,进程被唤醒,转入步骤(1);
(4)当进程不再使用一个信号量控制的资源时,信号量值加1,如果此时有进程正在睡眠等待此信号量,则唤醒此进程。
下面是一个使用信号量的例子,该程序创建一个特定的IPC结构的关键字和一个信号量,建立此信号量的索引,修改索引指向的信号量的值,最后清除信号量:
#include <stdio.h>
#include <sys/types.h>
#include <sys/sem.h>
#include <sys/ipc.h>
void main()
{
key_t unique_key; /* 定义一个IPC关键字*/
int id;
struct sembuf lock_it;
union semun options;
int i;
unique_key = ftok(".", 'a'); /* 生成关键字,字符'a'是一个随机种子*/
/* 创建一个新的信号量集合*/
id = semget(unique_key, 1, IPC_CREAT | IPC_EXCL | 0666);
printf("semaphore id=%d\n", id);
options.val = 1; /*设置变量值*/
semctl(id, 0, SETVAL, options); /*设置索引0的信号量*/
/*打印出信号量的值*/
i = semctl(id, 0, GETVAL, 0);
printf("value of semaphore at index 0 is %d\n", i);
/*下面重新设置信号量*/
lock_it.sem_num = 0; /*设置哪个信号量*/
lock_it.sem_op = - 1; /*定义操作*/
lock_it.sem_flg = IPC_NOWAIT; /*操作方式*/
if (semop(id, &lock_it, 1) == - 1)
{
printf("can not lock semaphore.\n");
exit(1);
}
i = semctl(id, 0, GETVAL, 0);
printf("value of semaphore at index 0 is %d\n", i);
/*清除信号量*/
semctl(id, 0, IPC_RMID, 0);
}
套接字通信并不为Linux所专有,在所有提供了TCP/IP协议栈的操作系统中几乎都提供了socket,而所有这样操作系统,对套接字的编程方法几乎是完全一样的。
进程间通信各种方式效率比较
类型
无连接
可靠
流控制
记录
消息类型优先级

4. 进程间通信 内存映射和共享内存的区别

内存映射文件是利用虚拟内存把文件映射到进程的地址空间中去,在此之后进程操作文件,就像操作进程空间里的地址一样了,比如使用c语言的memcpy等内存操作的函数。这种方法能够很好的应用在需要频繁处理一个文件或者是一个大文件的场合,这种方式处理IO效率比普通IO效率要高
共享内存是内存映射文件的一种特殊情况,内存映射的是一块内存,而非磁盘上的文件。共享内存的主语是进程(Process),操作系统默认会给每一个进程分配一个内存空间,每一个进程只允许访问操作系统分配给它的哪一段内存,而不能访问其他进程的。而有时候需要在不同进程之间访问同一段内存,怎么办呢?操作系统给出了创建访问共享内存的API,需要共享内存的进程可以通过这一组定义好的API来访问多个进程之间共有的内存,各个进程访问这一段内存就像访问一个硬盘上的文件一样。而.Net 4.0中引入了System.IO. MemoryMappedFiles命名空间,这个命名空间的类对windows 共享内存相关API做了封装,使.Net程序员可以更方便的使用内存映射文件。

5. 什么是共享内存,就是有的笔记本是共享内存,多大啊共享内存好吗和256M的哪个好

共享内存指在多处理器的计算机系统中,可以被不同中央处理器(CPU)访问的大容量内存。由于多个CPU需要快速访问存储器,这样就要对存储器进行缓存(Cache)。任何一个缓存的数据被更新后,由于其他处理器也可能要存取,共享内存就需要立即更新,否则不同的处理器可能用到不同的数据。共享内存 (shared memory)是 Unix下的多进程之间的通信方法 ,这种方法通常用于一个程序的多进程间通信,实际上多个程序间也可以通过共享内存来传递信息。

共享内存的创建
共享内存是存在于内核级别的一种资源,在shell中可以使用ipcs命令来查看当前系统IPC中的状态,在文件系统/proc目录下有对其描述的相应文件。函数shmget可以创建或打开一块共享内存区。函数原型如下: #include <sys/shm.h> 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所示。
编辑本段初始化
shmid_ds结构数据 初 值 shmid_ds结构数据 初 值
shm_lpid 0 shm_dtime 0
shm_nattach 0 shm_ctime 系统当前值
shm_atime 0 shm_segsz 参数 size
下面实例演示了使用shmget函数创建一块共享内存。程序中在调用shmget函数时指定key参数值为IPC_PRIVATE,这个参数的意义是创建一个新的共享内存区,当创建成功后使用shell命令ipcs来显示目前系统下共享内存的状态。命令参数-m为只显示共享内存的状态。 (1)在vi编辑器中编辑该程序如下: 程序清单14-8 create_shm.c 使用shmget函数创建共享内存 #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <stdlib.h> #include <stdio.h> #define BUFSZ 4096 int main ( void ) { int shm_id; /*共享内存标识符*/ shm_id=shmget(IPC_PRIVATE, BUFSZ, 0666 ) ; if (shm_id < 0 ) { /*创建共享内存*/ perror( "shmget" ) ; exit ( 1 ); } printf ( "successfully created segment : %d \n", shm_id ) ; system( "ipcs -m"); /*调用ipcs命令查看IPC*/ exit( 0 ); } (2)在shell中编译该程序如下: $gcc create_shm.c–o create_shm (3)在shell中运行该程序如下: $./ create_shm successfully created segment : 2752516 ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status 0x00000000 65536 root 600 393216 2 dest 0x00000000 2654209 root 666 4096 0 0x0056a4d5 2686978 root 600 488 1 0x0056a4d6 2719747 root 600 131072 1 0x00000000 2752516 root 666 4096 0 上述程序中使用shmget函数来创建一段共享内存,并在结束前调用了系统shell命令ipcs –m来查看当前系统IPC状态。
编辑本段共享内存的操作
由于共享内存这一特殊的资源类型,使它不同于普通的文件,因此,系统需要为其提供专有的操作函数,而这无疑增加了程序员开发的难度(需要记忆额外的专有函数)。使用函数shmctl可以对共享内存段进行多种操作,其函数原型如下: #include <sys/shm.h> int shmctl( int shm_id, int cmd, struct shmid_ds *buf ); 函数中参数shm_id为所要操作的共享内存段的标识符,struct shmid_ds型指针参数buf的作用与参数cmd的值相关,参数cmd指明了所要进行的操作,其解释如表14-5所示。
编辑本段cmd参数详解
cmd的值 意 义
IPC_STAT 取shm_id所指向内存共享段的shmid_ds结构,对参数buf指向的结构赋值
IPC_SET 使用buf指向的结构对sh_mid段的相关结构赋值,只对以下几个域有作用,shm_perm. uid shm_perm.gid以及shm_perm.mode 注意此命令只有具备以下条件的进程才可以请求: 1.进程的用户ID等于shm_perm.cuid或者等于shm_perm.uid 2.超级用户特权进程
IPC_RMID 删除shm_id所指向的共享内存段,只有当shmid_ds结构的shm_nattch域为零时,才会真正执行删除命令,否则不会删除该段 注意此命令的请求规则与IPC_SET命令相同
SHM_LOCK 锁定共享内存段在内存,此命令只能由超级用户请求
SHM_UNLOCK 对共享内存段解锁,此命令只能由超级用户请求
使用函数shmat将一个存在的共享内存段连接到本进程空间,其函数原型如下: #include <sys/shm.h> void *shmat( int shm_id, const void *addr, int flag ); 函数中参数shm_id指定要引入的共享内存,参数addr与flag组合说明要引入的地址值,通常只有2种用法,addr为0,表明让内核来决定第1个可以引入的位置。addr非零,并且flag中指定SHM_RND,则此段引入到addr所指向的位置(此操作不推荐使用,因为不会只对一种硬件上运行应用程序,为了程序的通用性推荐使用第1种方法),在flag参数中可以指定要引入的方式(读写方式指定)。 %说明:函数成功执行返回值为实际引入的地址,失败返回–1。shmat函数成功执行会将shm_id段的shmid_ds结构的shm_nattch计数器的值加1。 当对共享内存段操作结束时,应调用shmdt函数,作用是将指定的共享内存段从当前进程空间中脱离出去。函数原型如下: #include <sys/shm.h> int shmdt( void *addr); 参数addr是调用shmat函数的返回值,函数执行成功返回0,并将该共享内存的shmid_ds结构的shm_nattch计数器减1,失败返回–1。 下面实例演示了操作共享内存段的流程。程序的开始部分先检测用户是否有输入,如出错则打印该命令的使用帮助。接下来从命令行读取将要引入的共享内存ID,使用shmat函数引入该共享内存,并在分离该内存之前睡眠3秒以方便查看系统IPC状态。 (1)在vi编辑器中编辑该程序如下: 程序清单14-9 opr_shm.c 操作共享内存段 #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <stdlib.h> #include <stdio.h> int main ( int argc, char *argv[] ) { int shm_id ; char * shm_buf; if ( argc != 2 ){ /* 命令行参数错误 */ printf ( "USAGE: atshm <identifier>" ); /*打印帮助消息*/ exit (1 ); } shm_id = atoi(argv[1]); /*得到要引入的共享内存段*/ /*引入共享内存段,由内核选择要引入的位置*/ if ( (shm_buf = shmat( shm_id, 0, 0)) < (char *) 0 ){ perror ( "shmat" ); exit (1); } printf ( " segment attached at %p\n", shm_buf ); /*输出导入的位置*/ system("ipcs -m"); sleep(3); /* 休眠 */ if ( (shmdt(shm_buf)) < 0 ) { /*与导入的共享内存段分离*/ perror ( "shmdt"); exit(1); } printf ( "segment detached \n" ); system ( "ipcs -m " ); /*再次查看系统IPC状态*/ exit ( 0 ); } (2)在shell中编译该程序如下: $gcc opr_shm.c–o opr_shm (3)在shell中运行该程序如下: $./ opr_shm 2752516 segment attached at 0xb7f29000 ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status 0x00000000 65536 root 600 393216 2 dest 0x00000000 2654209 root 666 4096 0 0x0056a4d5 2686978 root 600 488 1 0x0056a4d6 2719747 root 600 131072 1 0x00000000 2752516 root 666 4096 1 segment detached ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status 0x00000000 65536 root 600 393216 2 dest 0x00000000 2654209 root 666 4096 0 0x0056a4d5 2686978 root 600 488 1 0x0056a4d6 2719747 root 600 131072 1 0x00000000 2752516 root 666 4096 0 上述程序中从命令行中读取所要引入的共享内存ID,并使用shmat函数引入该内存到当前的进程空间中。注意在使用shmat函数时,将参数addr的值设为0,所表达的意义是由内核来决定该共享内存在当前进程中的位置。由于在编程的过程中,很少会针对某一个特定的硬件或系统编程,所以由内核决定引入位置也就是shmat推荐的使用方式。在导入后使用shell命令ipcs –m来显示当前的系统IPC的状态,可以看出输出信息中nattch字段为该共享内存时的引用值,最后使用shmdt函数分离该共享内存并打印系统IPC的状态。
编辑本段共享内存使用注意事项
共享内存相比其他几种方式有着更方便的数据控制能力,数据在读写过程中会更透明。当成功导入一块共享内存后,它只是相当于一个字符串指针来指向一块内存,在当前进程下用户可以随意的访问。缺点是,数据写入进程或数据读出进程中,需要附加的数据结构控制,共享内存通信数据结构示意如图14-9所示。
编辑本段结构示意
%说明:图中两个进程同时遵循一定的规则来读写该内存。同时,在多进程同步或互斥上也需要附加的代码来辅助共享内存机制。 在共享内存段中都是以字符串的默认结束符为一条信息的结尾。每个进程在读写时都遵守这个规则,就不会破坏数据的完整性。

6. java共享内存的问题,如何存,取共享数据

1 共享内存对应应用开发的意义
对熟知UNIX系统应用开发的程序员来说,IPC(InterProcess
Communication)机制是非常熟悉的,IPC基本包括共享内存、信号灯操作、消息队列、信号处理等部分,是开发应用中非常重要的必不可少的工具。其中共享内存IPC机制的关键,对于数据共享、系统快速查询、动态配置、减少资源耗费等均有独到的优点。

对应UNIX系统来说,共享内存分为一般共享内存和映像文件共享内存两种,而对应 Windows,实际上只有映像文件共享内存一种。所以java应用中也是只能创建映像文件共享内存。

在java语言中,基本上没有提及共享内存这个概念,但是,在某一些应用中,共享内存确实非常有用,例如采用java语言的分布式应用系统中,存在着大量的分布式共享对象,很多时候需要查询这些对象的状态,以查看系统是否运行正常或者了解这些对象的目前的一些统计数据和状态。如果采用网络通信的方式,显然会增加应用的额外负担,也增加了一些不必要的应用编程。而如果采用共享内存的方式,则可以直接通过共享内存查看对象的状态数据和统计数据,从而减少了一些不必要的麻烦。

7. 共享内存是什么意思

共享内存也说显卡显存,指在多处理器的计算机系统中,可以被不同中央CPU访问的大容量内存。由于多个CPU需要快速访问存储器,这样就要对存储器进行缓存。任何一个缓存的数据被更新后,由于其他处理器也可能要存取,共享内存就需要立即更新,否则不同的处理器可能用到不同的数据。共享内存是Unix下的多进程之间的通信方法,这种方法通常用于一个程序的多进程间通信,实际上多个程序间也可以通过共享内存来传递信息。

8. linux共享内存和mmap的区别

共享内存的创建
根据理论:
1. 共享内存允许两个或多个进程共享一给定的存储区,因为数据不需要来回复制,所以是最快的一种进程间通信机制。共享内存可以通过mmap()映射普通文件(特殊情况下还可以采用匿名映射)机制实现,也可以通过系统V共享内存机制实现。应用接口和原理很简单,内部机制复杂。为了实现更安全通信,往往还与信号灯等同步机制共同使用。

mmap的机制如:就是在磁盘上建立一个文件,每个进程存储器里面,单独开辟一个空间来进行映射。如果多进程的话,那么不会对实际的物理存储器(主存)消耗太大。

shm的机制:每个进程的共享内存都直接映射到实际物理存储器里面。

结论:

1、mmap保存到实际硬盘,实际存储并没有反映到主存上。优点:储存量可以很大(多于主存)(这里一个问题,需要高手解答,会不会太多拷贝到主存里面???);缺点:进程间读取和写入速度要比主存的要慢。

2、shm保存到物理存储器(主存),实际的储存量直接反映到主存上。优点,进程间访问速度(读写)比磁盘要快;缺点,储存量不能非常大(多于主存)

使用上看:如果分配的存储量不大,那么使用shm;如果存储量大,那么使用shm。

参看网络:http://ke..com/view/1499209.htm
mmap就是一个文件操作

看这些网络的描述:
mmap()系统调用使得进程之间通过映射同一个普通文件实现共享内存。普通文件被映射到进程地址空间后,进程可以向访问普通内存一样对文件进行访问,不必再调用read(),write()等操作。 成功执行时,mmap()返回被映射区的指针,munmap()返回0。失败时,mmap()返回MAP_FAILED[其值为(void *)-1],munmap返回-1。errno被设为以下的某个值 EACCES:访问出错EAGAIN:文件已被锁定,或者太多的内存已被锁定EBADF:fd不是有效的文件描述词EINVAL:一个或者多个参数无效 ENFILE:已达到系统对打开文件的限制ENODEV:指定文件所在的文件系统不支持内存映射ENOMEM:内存不足,或者进程已超出最大内存映射数量 EPERM:权能不足,操作不允许ETXTBSY:已写的方式打开文件,同时指定MAP_DENYWRITE标志SIGSEGV:试着向只读区写入 SIGBUS:试着访问不属于进程的内存区参数fd为即将映射到进程空间的文件描述字,

一般由open()返回,同时,fd可以指定为-1,此时须指定 flags参数中的MAP_ANON,表明进行的是匿名映射(不涉及具体的文件名,避免了文件的创建及打开,很显然只能用于具有亲缘关系的进程间通信)

相关文章参考:
mmap函数是unix/linux下的系统调用,来看《Unix Netword programming》卷二12.2节有详细介绍。
mmap系统调用并不是完全为了用于共享内存而设计的。它本身提供了不同于一般对普通文件的访问方式,进程可以像读写内存一样对普通文件的操作。而Posix或系统V的共享内存IPC则纯粹用于共享目的,当然mmap()实现共享内存也是其主要应用之一。
mmap系统调用使得进程之间通过映射同一个普通文件实现共享内存。普通文件被映射到进程地址空间后,进程可以像访问普通内存一样对文件进行访问,不必再 调用read(),write()等操作。mmap并不分配空间, 只是将文件映射到调用进程的地址空间里, 然后你就可以用memcpy等操作写文件, 而不用write()了.写完后用msync()同步一下, 你所写的内容就保存到文件里了. 不过这种方式没办法增加文件的长度, 因为要映射的长度在调用mmap()的时候就决定了.

简单说就是把一个文件的内容在内存里面做一个映像,内存比磁盘快些。
基本上它是把一个档案对应到你的virtual memory 中的一段,并传回一个指针。

重写总结:
1、mmap实际就是操作“文件”。
2、映射文件,除了主存的考虑外。shm的内存共享,效率应该比mmap效率要高(mmap通过io和文件操作,或“需要写完后用msync()同步一下”);当然mmap映射操作文件,比直接操作文件要快些;由于多了一步msync应该可以说比shm要慢了吧???
3、另一方面,mmap的优点是,操作比shm简单(没有调用比shm函数复杂),我想这也是许多人喜欢用的原因,包括nginx。

缺点,还得通过实际程序测试,确定!!!

修正理解(这也真是的,这个网站没办法附加;只能重写了):
今天又细心研究了一下,发现网络这么一段说明:
2、系统调用mmap()用于共享内存的两种方式:
(1)使用普通文件提供的内存映射:适用于任何进程之间;此时,需要打开或创建一个文件,然后再调用mmap();典型调用代码如下:
fd=open(name, flag, mode);
if(fd<0)
...
ptr=mmap(NULL, len , PROT_READ|PROT_WRITE, MAP_SHARED , fd , 0); 通过mmap()实现共享内存的通信方式有许多特点和要注意的地方,我们将在范例中进行具体说明。
(2)使用特殊文件提供匿名内存映射:适用于具有亲缘关系的进程之间;由于父子进程特殊的亲缘关系,在父进程中先调用mmap(),然后调用fork()。那么在调用fork()之后,子进程继承父进程匿名映射后的地址空间,同样也继承mmap()返回的地址,这样,父子进程就可以通过映射区域进行通信了。注意,这里不是一般的继承关系。一般来说,子进程单独维护从父进程继承下来的一些变量。而mmap()返回的地址,却由父子进程共同维护。
看了一下windows“内存映射文件”:http://ke..com/view/394293.htm
内存映射文件与虚拟内存有些类似,通过内存映射文件可以保留一个地址空间的区域,同时将物理存储器提交给此区域,只是内存文件映射的物理存储器来自一个已经存在于磁盘上的文件,而非系统的页文件,而且在对该文件进行操作之前必须首先对文件进行映射,就如同将整个文件从磁盘加载到内存。由此可以看出,使用内存映射文件处理存储于磁盘上的文件时,将不必再对文件执行I/O操作,这意味着在对文件进行处理时将不必再为文件申请并分配缓存,所有的文件缓存操作均由系统直接管理,由于取消了将文件数据加载到内存、数据从内存到文件的回写以及释放内存块等步骤,使得内存映射文件在处理大数据量的文件时能起到相当重要的作用。另外,实际工程中的系统往往需要在多个进程之间共享数据,如果数据量小,处理方法是灵活多变的,如果共享数据容量巨大,那么就需要借助于内存映射文件来进行。实际上,内存映射文件正是解决本地多个进程间数据共享的最有效方法。

这里再总结一次:
1、mmap有两种方式,一种是映射内存,它把普通文件映射为实际物理内存页,访问它就和访问物理内存一样(这也就和shm的功能一样了)(同时不用刷新到文件)
2、mmap可以映射文件,不确定会不会像windows“内存映射文件”一样的功能,如果是,那么他就能映射好几G甚至好几百G的内存数据,对大数据处理将提供强大功能了???
3、shm只做内存映射,和mmap第一个功能一样!只不过不是普通文件而已,但都是物理内存。

9. linux共享内存使用的过程

Linux共享内存使用的过程?

一、什么是共享内存
顾名思义,共享内存就是允许两个不相关的进程访问同一个逻辑内存。共享内存是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式。不同进程之间共享的内存通常安排为同一段物理内存。进程可以将同一段共享内存连接到它们自己的地址空间中,所有进程都可以访问共享内存中的地址,就好像它们是由用C语言函数malloc分配的内存一样。而如果某个进程向共享内存写入数据,所做的改动将立即影响到可以访问同一段共享内存的任何其他进程。

特别提醒:共享内存并未提供同步机制,也就是说,在第一个进程结束对共享内存的写操作之前,并无自动机制可以阻止第二个进程开始对它进行读取。所以我们通常需要用其他的机制来同步对共享内存的访问,例如前面说到的信号量。

二、共享内存的使用
与信号量一样,在Linux中也提供了一组函数接口用于使用共享内存,而且使用共享共存的接口还与信号量的非常相似,而且比使用信号量的接口来得简单。它们声明在头文件 sys/shm.h中。
1、shmget函数
该函数用来创建共享内存,它的原型为:
int shmget(key_t key, size_t size, int shmflg);
第一个参数,与信号量的semget函数一样,程序需要提供一个参数key(非0整数),它有效地为共享内存段命名,shmget函数成功时返回一个与key相关的共享内存标识符(非负整数),用于后续的共享内存函数。调用失败返回-1.

不相关的进程可以通过该函数的返回值访问同一共享内存,它代表程序可能要使用的某个资源,程序对所有共享内存的访问都是间接的,程序先通过调用shmget函数并提供一个键,再由系统生成一个相应的共享内存标识符(shmget函数的返回值),只有shmget函数才直接使用信号量键,所有其他的信号量函数使用由semget函数返回的信号量标识符。

第二个参数,size以字节为单位指定需要共享的内存容量

第三个参数,shmflg是权限标志,它的作用与open函数的mode参数一样,如果要想在key标识的共享内存不存在时,创建它的话,可以与IPC_CREAT做或操作。共享内存的权限标志与文件的读写权限一样,举例来说,0644,它表示允许一个进程创建的共享内存被内存创建者所拥有的进程向共享内存读取和写入数据,同时其他用户创建的进程只能读取共享内存。

热点内容
同样的人为什么量出来不一样 发布:2025-01-16 04:38:38 浏览:188
微信语音说话为什么出去听不到 发布:2025-01-16 04:16:56 浏览:570
为什么微信不转账 发布:2025-01-16 04:16:13 浏览:671
为什么这段时间又要送人上天 发布:2025-01-16 04:16:10 浏览:242
淘宝上的盖碗为什么有那么贵 发布:2025-01-16 04:14:45 浏览:502
为什么米粉时间一久就变水了 发布:2025-01-16 04:14:44 浏览:967
为什么小白测评小米的续航高 发布:2025-01-16 04:13:25 浏览:376
为什么男人说我贪钱 发布:2025-01-16 04:04:19 浏览:765
苹果电脑的屏幕色彩为什么那么好 发布:2025-01-16 03:58:31 浏览:397
老鹰眼睛为什么很远 发布:2025-01-16 03:09:03 浏览:520