Posix多线程编程学习笔记(六)—共享内存(1)

转载 2012年05月22日 11:31:03

一、什么是共享内存区

共享内存区是最快的可用IPC形式。它允许多个不相关的进程去访问同一部分逻辑内存。如果需要在两个运行中的进程之间传输数据,共享内存将是一种效率极高的解决方案。一旦这样的内存区映射到共享它的进程的地址空间,这些进程间数据的传输就不再涉及内核。这样就可以减少系统调用时间,提高程序效率。

共享内存是由IPC为一个进程创建的一个特殊的地址范围,它将出现在进程的地址空间中。其他进程可以把同一段共享内存段“连接到”它们自己的地址空间里去。所有进程都可以访问共享内存中的地址。如果一个进程向这段共享内存写了数据,所做的改动会立刻被有访问同一段共享内存的其他进程看到。

要注意的是共享内存本身没有提供任何同步功能。也就是说,在第一个进程结束对共享内存的写操作之前,并没有什么自动功能能够预防第二个进程开始对它进行读操作。共享内存的访问同步问题必须由程序员负责。可选的同步方式有互斥锁、条件变量、读写锁、纪录锁、信号灯。

      

二、mmap

       在将共享内存前我们要先来介绍下面几个函数。

mmap函数把一个文件或一个Posix共享内存区对象映射到调用进程的地址空间。使用该函数有三个目的:

       1.使用普通文件以提供内存映射I/O

       2.使用特殊文件以提供匿名内存映射。

       3.使用shm_open以提供无亲缘关系进程间的Posix共享内存区。

 

1

名称:

mmap

功能:

I/O文件映射到一个存储区域中

头文件:

#include <sys/mman.h>

函数原形:

void *mmap(void *addr,size_t len,int prot,int flag,int filedes,off_t off);

参数:

addr      指向映射存储区的起始地址

len       映射的字节

prot      对映射存储区的保护要求

flag      flag标志位

filedes    要被映射文件的描述符

off       要映射字节在文件中的起始偏移量

返回值:

若成功则返回映射区的起始地址,若出错则返回MAP_FAILED

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

addr参数用于指定映射存储区的起始地址。通常将其设置为NULL,这表示由系统选择该映射区的起始地址。

       filedes指要被映射文件的描述符。在映射该文件到一个地址空间之前,先要打开该文件。len是映射的字节数。

       off是要映射字节在文件中的起始偏移量。通常将其设置为0

       prot参数说明对映射存储区的保护要求。可将prot参数指定为PROT_NONE,或者是PROT_READ(映射区可读),PROT_WRITE(映射区可写),PROT_EXEC(映射区可执行)任意组合的按位或,也可以是PROT_NONE(映射区不可访问)。对指定映射存储区的保护要求不能超过文件open模式访问权限。

       flag参数影响映射区的多种属性:    

MAP_FIXED 返回值必须等于addr.因为这不利于可移植性,所以不鼓励使用此标志。

MAP_SHARED 这一标志说明了本进程对映射区所进行的存储操作的配置。此标志指定存储操作修改映射文件。

MAP_PRIVATE 本标志导致对映射区建立一个该映射文件的一个私有副本。所有后来对该映射区的引用都是引用该副本,而不是原始文件。

要注意的是必须指定MAP_FIXEDMAP_PRIVATE标志其中的一个,指定前者是对存储映射文件本身的一个操作,而后者是对其副本进行操作。

 

mmap成功返回后,fd参数可以关闭。该操作对于由mmap建立的映射关系没有影响。为从某个进程的地址空间删除一个映射关系,我们调用munmap.

2

名称:

munmap

功能:

解除存储映射

头文件:

#include <sys/mman.h>

函数原形:

int munmap(caddr_t addr,size_t len);

参数:

addr      指向映射存储区的起始地址

len       映射的字节

返回值:

若成功则返回0,若出错则返回-1

      

 

 

 

 

 

 

 

 

 

 

 其中addr参数是由mmap返回的地址,len是映射区的大小。再次访问这些地址导致向调用进程产生一个SIGSEGV信号。

       如果被映射区是使用MAP_PRIVATE标志映射的,那么调用进程对它所作的变动都被丢弃掉。

 

内核的虚存算法保持内存映射文件(一般在硬盘上)与内存映射区(在内存中)的同步(前提它是MAP_SHARED内存区)。这就是说,如果我们修改了内存映射到某个文件的内存区中某个位置的内容,那么内核将在稍后某个时刻相应地更新文件。然而有时候我们希望确信硬盘上的文件内容与内存映射区中的文件内容一致,于是调用msync来执行这种同步。

 

3

名称:

msync

功能:

同步文件到存储器

头文件:

#include <sys/mman.h>

函数原形:

int msync(void *addr,size_t len,int flags);

参数:

addr      指向映射存储区的起始地址

len       映射的字节

prot      flags

返回值:

若成功则返回0,若出错则返回-1

     

 

 

 

 

 

 

 

 

 

 

 

 其中addrlen参数通常指代内存中的整个内存映射区,不过也可以指定该内存区的一个子集。flags参数为MS_ASYNC(执行异步写)MS_SYNC(执行同步写),MS_INVALIDATE(使高速缓存的数据实效)。其中MS_ASYNCMS_SYNC这两个常值中必须指定一个,但不能都指定。它们的差别是,一旦写操作已由内核排入队列,MS_ASYNC即返回,而MS_SYNC则要等到写操作完成后才返回。如果还指定了MS_INVALIDATE,那么与其最终拷贝不一致的文件数据的所有内存中拷贝都失效。后续的引用将从文件取得数据。

 

4

名称:

memcpy

功能:

复制映射存储区

头文件:

#include <string.h>

函数原形:

void *memcpy(void *dest,const void *src,size_t n);

参数:

dest       待复制的映射存储区

src        复制后的映射存储区

n          待复制的映射存储区的大小

返回值:

返回dest的首地址

      

 

 

 

 

 

 

 

 

 

 

 

memcpy拷贝n个字节从destsrc

 

下面就是利用mmap函数影射I/O实现的cp命令。

/*mycp.c*/

#include <unistd.h>

#include <fcntl.h>

#include <sys/mman.h>

#include <sys/stat.h>

#include <sys/types.h>

 

int main(int argc,char *argv[])

{

int fdin,fdout;

void *arc,dst;

struct stat statbuf;

 

if(argc!=3)

{

    printf(“please input two file!/n”);

    exit(1);

}

if((fdin=open(argv[1],O_RDONLY))<0) /*打开原文件*/

    perror(argv[1]);

if((fdout=open(argv[2],O_RDWR|O_CREAT|O_TRUNC))<0)/*创建并打开目标文件*/

    perror(argv[2]);

 

if(fstat(fdin,&statbuf)<0) /*获得文件大小信息*/

    printf(“fstat error”);

 

if(lseek(fdout,statbuf.st_size-1,SEEK_SET)==-1)/*初始化输出映射存储区*/

    printf(“lseek error”);

if(write(fdout,”1”)!=1)

    printf(“write error”);

 

if((src=mmap(0,statbuf.st_size,PROT_READ,MAP_SHARED,fdin,0))==MAP_FAILED)

    /*映射原文件到输入的映射存储区*/

    printf(“mmap error);

if((dst=mmap(0,statbuf.st_size,PROT_READ|PROT_WRITE,MAP_SHARED,fdout,0)) ==MAP_FAILED) /*映射目标文件到输出的映射存储区*/

    printf(“mmap error);

memcpy(dst,src,statbuf.st_size);/*复制映射存储区*/

munmap(src,statbuf.st_size); /*解除输入映射*/

munmap(dst,statbuf.st_size); /*解除输出映射*/

close(fdin);

close(fdout);

}

下面是运行结果:

#cc –o mycp mycp.c

#./mycp test1 test2


相关文章推荐

Posix多线程编程学习笔记(三)—信号灯(1)

Posix有名信号灯        函数sem_open创建一个新的有名信号灯或打开一个已存在的有名信号灯。有名信号灯总是既可用于线程间的同步,又可以用于进程间的同步。   1.posix有名信...
  • elbort
  • elbort
  • 2012年05月22日 10:35
  • 231

Posix多线程编程学习笔记(一)—线程基础(1)

一.什么是线程       在一个程序里的多个执行路线就叫做线程。更准确的定义是:线程是“一个进程内部的一个控制序列”。        典型的unix进程可以看成只有一个控制线程:一个进程在同...

Posix多线程编程学习笔记(二)—线程属性(1)

一.线程属性        线程具有属性,用pthread_attr_t表示,在对该结构进行处理之前必须进行初始化,在使用后需要对其去除初始化。我们用pthread_attr_init函数对其初...

Linux 多线程编程( POSIX )( 六 )----->代码区 ( 共享内存实例 )

注意:以下编译加上  -lrt 例如:gcc  -o server  server.c  -lrt 1.创建一个共享内存区的例子 #include #include #inclu...

Posix多线程编程(6)—共享内存

一、什么是共享内存区 共享内存区是最快的可用IPC形式。它允许多个不相关的进程去访问同一部分逻辑内存。如果需要在两个运行中的进程之间传输数据,共享内存将是一种效率极高的解决方案。一旦这样的内存区映射到...

Posix多线程编程学习笔记(二)—线程属性(3)

六、线程的作用域        函数pthread_attr_setscope和pthread_attr_getscope分别用来设置和得到线程的作用域,这两个函数的定义如下:        ...
  • elbort
  • elbort
  • 2012年05月22日 10:33
  • 223

Posix多线程编程学习笔记(一)—线程基础(2)

6. 名称:: pthread_detach 功能: 使线程进入分离状态。 头文件: #include ...

Posix多线程编程学习笔记(三)—信号灯(2)

5. 名称:: sem_wait/sem_trywait 功能: 等待共享资源 头文件: #include ...

Posix多线程编程学习笔记(三)—信号灯(3)

4.posix有名信号灯应用于多进程 下面就是应用Posix有名信号灯的一个小程序。用它来限制访问共享代码的进程数目。 #include #include #include...
  • elbort
  • elbort
  • 2012年05月22日 10:52
  • 690

Posix多线程编程学习笔记(二)—线程属性(2)

四、线程的调度策略        函数pthread_attr_setschedpolicy和pthread_attr_getschedpolicy分别用来设置和得到线程的调度策略。   4...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Posix多线程编程学习笔记(六)—共享内存(1)
举报原因:
原因补充:

(最多只允许输入30个字)