您的位置:首页 > 运维架构 > Linux

IPC通信:Posix共享内存2

2016-08-11 14:53 666 查看
原文:http://www.cnblogs.com/polestar/archive/2012/04/23/2466022.html

Posix共享内存区涉及两个步骤:

1、指定一个名字参数调用shm_open,以创建一个新的共享内存区对象或打开一个以存在的共享内存区对象。

2、调用mmap把这个共享内存区映射到调用进程的地址空间。传递给shm_open的名字参数随后由希望共享该内存区的任何其他进程使用。

相关函数:

1 shm_open()函数
2 功能:    打开或创建一个共享内存区
3 头文件:    #include <sys/mman.h>
4 函数原形:    int shm_open(const char *name,int oflag,mode_t mode);
5 返回值:    成功返回0,出错返回-1
6 参数:
7     name    共享内存区的名字
8     oflag    标志位
9     mode    权限位
10
11 参数解释:oflag参数必须含有O_RDONLY和O_RDWR标志,还可以指定如下标志:O_CREAT,O_EXCL或O_TRUNC.mode参数指定权限位,
12 它指定O_CREAT标志的前提下使用。shm_open的返回值是一个整数描述字,它随后用作mmap的第五个参数。
13
14 shm_unlink()函数
15 功能:    删除一个共享内存区
16 头文件:    #include <sys/mman.h>
17 函数原形:    int shm_unlink(const char *name);
18 参数:     name    共享内存区的名字
19 返回值:    成功返回0,出错返回-1
20
21 shm_unlink函数删除一个共享内存区对象的名字,删除一个名字仅仅防止后续的open,mq_open或sem_open调用取得成功。


示例代码:

1 /*shm_open.c创建共享内存区*/
2 #include <stdlib.h>
3 #include <sys/mman.h>
4 #include <stdio.h>
5 #include <fcntl.h>
6
7 int main(int argc,char **argv)
8 {
9     int shm_id;
10
11     if(argc!=2)
12     {
13         printf("usage:shm_open <pathname>\n");
14         exit(1);
15     }
16     shm_id=shm_open(argv[1],O_RDWR|O_CREAT,0644);
17     printf("shmid:%d\n",shm_id);
18     shm_unlink(argv[1]);
19 }


编译运行:

1 root@linux:/mnt/hgfs/C_libary# vi shm_open.c
2 root@linux:/mnt/hgfs/C_libary# gcc -o shm_open shm_open.c
3 /tmp/cceAejzp.o: In function `main':
4 shm_open.c:(.text+0x43): undefined reference to `shm_open'
5 shm_open.c:(.text+0x6c): undefined reference to `shm_unlink'
6 collect2: ld returned 1 exit status
7 root@linux:/mnt/hgfs/C_libary# gcc -lrt -o shm_open shm_open.c
8 root@linux:/mnt/hgfs/C_libary# ./shm_open shm_test
9 shmid:3
10 root@linux:/mnt/hgfs/C_libary#


相关函数2:

1 ftruncate()函数 3 功能:    调整文件或共享内存区大小
4 头文件:    #include <unistd.h>
5 函数原形:    int ftruncate(int fd,off_t length);
6 参数:
7     fd          描述符
8     length       大小
9 返回值:    成功返回0,出错返回-1
10
11 当打开一个已存在的共享内存区对象时,我们可调用fstat来获取有关该对象的信息
12
13 fstat()函数
14 功能:    获得文件或共享内存区的信息
15 头文件:    #include <unistd.h>
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 函数原形:    int stat(const char *file_name,struct stat *buf);
19 参数:
20 file_name          文件名
21 buf               stat结构
22 返回值:    成功返回0,出错返回-1
23
24 对于普通文件stat结构可以获得12个以上的成员信息,然而当fd指代一个共享内存区对象时,只有四个成员含有信息。
25 struct stat{
26     mode_t st_mode;
27     uid_t st_uid;
28     gid_t st_gid;
29     off_t st_size;
30 };


示例代码:

1 /*shm_show.c显示共享区信息*/
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <unistd.h>
5 #include <sys/stat.h>
6 #include <sys/types.h>
7 #include <fcntl.h>
8 #include <sys/mman.h>
9
10 int main(int argc,char **argv)
11 {
12     int shm_id;
13         struct stat buf;
14
15         if(argc!=2)
16         {
17             printf("usage:shm_open <pathname>\n");
18             exit(1);
19         }
20         shm_id=shm_open(argv[1],O_RDWR|O_CREAT,0644);/*创建共享内存*/
21         printf("size :%d\n",buf.st_size); /*修改前共享内存区大小*/
22         ftruncate(shm_id,100);/*修改共享内存的大小*/
23         fstat(shm_id,&buf); /*把共享内存的信息记录到buf中*/
24         printf("uid_t:%d\n",buf.st_uid); /*共享内存区所有者ID*/
25         printf("git_t:%d\n",buf.st_gid); /*共享内存区所有者组ID*/
26         printf("size :%d\n",buf.st_size); /*修改后共享内存区大小*/
27 }


编译运行:

1 root@linux:/mnt/hgfs/C_libary# gcc -lrt -o shm_show shm_show.c
2 shm_show.c: In function ‘main’:
3 shm_show.c:20: warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘__off_t’
4 shm_show.c:25: warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘__off_t’
5
6 /* 内容来自互联网
7         有人提出来在sys/types.h里面加上 typedef long __off_t; typedef long __time_t;
8
9         小鱼我看了一下源文件,认为上面的说法还是有问题的,露了off_t和time_t
10         #ifndef __off_t_defined
11         # ifndef __USE_FILE_OFFSET64
12         typedef __off_t off_t;
13         # else
14         typedef __off64_t off_t;
15         # endif
16         # define __off_t_defined
17         #endif
18
19         如果定义了__USE_FILE_OFFSET64 就把off_t定义为__off64_t ,否则定义为32位(传说中的大文件支持处理)
20         ------------------------------
21         其实没必要casting。直接用%ld换掉%d就行了,因为是long int所以%d会抛警告的
22 */
23 root@linux:/mnt/hgfs/C_libary# gcc -lrt -o shm_show shm_show.c
24 root@linux:/mnt/hgfs/C_libary#
25 root@linux:/mnt/hgfs/C_libary# ./shm_show test
26 size :4983648
27 uid_t:0
28 git_t:0
29 size :100
30 root@linux:/mnt/hgfs/C_libary#


共享内存区的写入和读出

  前面我们介绍了mmap函数,下面我们就可以通过这些函数,把进程映射到共享内存区。然后我们就可以通过共享内存区进行进程间通信了。

示例代码:

1 /*shm_write.c写入/读出共享内存区*/
2 #include <stdio.h>
3 #include <string.h>
4 #include <stdlib.h>
5 #include <sys/stat.h>
6 #include <fcntl.h>
7 #include <sys/mman.h>
8 #include <unistd.h>
9
10 int main(int argc,char **argv)
11 {
12     int shm_id;
13     struct stat buf;
14     char *ptr;
15
16     if(argc!=2)
17     {
18         printf("usage:shm_open <pathname>\n");
19         exit(1);
20     }
21     shm_id=shm_open(argv[1],O_RDWR|O_CREAT,0644);/*创建共享内存区*/
22     ftruncate(shm_id,100);/*修改共享区大小*/
23     fstat(shm_id,&buf);
24     ptr=mmap(NULL,buf.st_size,PROT_READ|PROT_WRITE,MAP_SHARED,shm_id,0);/*连接共享内存区*/
25     strcpy(ptr,"hello linux");/*写入共享内存区*/
26     printf("%s\n",ptr);/*读出共享内存区*/
27     shm_unlink(argv[1]);/*删除共享内存区*/
28 }


编译运行:

1 root@linux:/mnt/hgfs/C_libary# gcc -lrt -o shm_write shm_write.c
2 root@linux:/mnt/hgfs/C_libary# ./shm_write test
3 hello linux
4 root@linux:/mnt/hgfs/C_libary#
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  通信 linux 内存