分享

Linux 共享内存(POSIX)

 fhr625 2012-07-20
        C programming in the UNIX environment的编程手册,一般都会为进程间用共享内存的方法通信提供两组方法:
  1. POSIX定义的:
  int shm_open(const char *name, int oflag, mode_t mode);
  int shm_unlink(const char *name);
  int ftruncate(int fd, off_t length);
  2. SYSTEM V定义的
  int shmget(key_t key, int size, int shmflg);
  void *shmat(int shmid, const void *shmaddr, int shmflg);
  int shmdt(const void *shmaddr);
  int shmctl(int shmid, int cmd, struct shmid_ds *buf);
  由于POSIX标准比较通用,一般建议使用该标准定义的方法集。
 
 
 
 
 
使用shm_open来操作共享内存

shm_open最主要的操作也是默认的操作就是在/dev/shm/下面,建立一个文件。

文件名字是用户自己输入的。

要点一定要用ftruncate把文件大小于设置为共享内存大小。

服务端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
char buf[10];
char *ptr;
int main()
{
int fd;
fd = shm_open("region", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
if (fd<0) {
printf("error open region\n");
return 0;
}
ftruncate(fd, 10);
ptr = mmap(NULL, 10, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED) {
printf("error map\n");
return 0;
}
*ptr = 0x12;
return 0;
}

客户端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
char buf[10];
char *ptr;
int main()
{
int fd;
fd = shm_open("region", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
if (fd<0) {
printf("error open region\n");
return 0;
}
ftruncate(fd, 10);
ptr = mmap(NULL, 10, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED) {
printf("error map\n");
return 0;
}
while (*ptr != 0x12);
printf("ptr : %d\n", *ptr);
return 0;
}
~
~
 
 
mmap 详解:

mmap函数是unix/linux下的系统调用,来看《Unix Netword programming》卷二12.2节有详细介绍。

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

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

以后对这段 memory 做存取时,其实就是对那个档做存取。
它就是一种快速 file I/O 的东东,而且使用上和存取 memory 一样方便,只不过会占掉你的 virutal memory。
#include <sys/types.h>
#include <sys/stat.h> //文件状态结构
#include <unistd.h>
#include <sys/mman.h> //mmap头文件

void * mmap(void *start, size_t length, int prot , int flags, int fd, off_t offset);

mmap开启记忆体对映。
start指定记忆体位置,通常都是用NULL。offset指定档案要在那里开始对映,通常都是用0。

int munmap(void *start, size_t length);

int msync(const void *start, size_t length, int flags);
如果开启记忆体对映是希望写入档案中,那麽修改过的记忆体会在一段时间内与档案稍稍有点不同。如果您希望立即将资料写入档案中,可使用msync。

start为记忆体开始位置,length为长度。

flags则有三个:
MS_ASYNC : 请Kernel快将资料写入。
MS_SYNC : 在msync结束返回前,将资料写入。
MS_INVALIDATE : 让核心自行决定是否写入,仅在特殊状况下使用

例子:
if( (fp = open("./data.bin",O_RDONLY) ) < 0 )
{
cout<<" Can not open !"<<endl;
exit(0);
}
if( (fstat(fp,&stat_data) ) < 0 )
{
cout<<" fstat error !";
exit(0);
}
if( ( start_fp = mmap(NULL,stat_data.st_size,
PROT_READ,MAP_SHARED,fd_denseindex,0 )) == (void *)-1)
{
cout<<" mmap error !"<<endl;
exit(0);
}
这样便能从start_fp开始读取数据啦!

来自:http://hi.baidu.com/yoursguang/blog/item/81f77f387720022296ddd814.html

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多