c语言编程基础之IPC共享内存

共享内存(Shared Memory)是最简单的进程间通信方式,它允许多个进程访问相同的内存,一个进程改变其中的数据后,其他的进程都可以看到数据的变化。

共享内存是进程间最快速的通信方式:
`进程共享同一块内存空间。
`访问共享内存和访问私有内存一样快。
`不需要系统调用和内核入口。
`不造成不必要的内存复制。

内核不对共享内存的访问进行同步,因此程序员必须自己提供同步。

使用共享内存:
`某个进程分配内存段。
`使用这个内存段的进程要连接(attach)这个内存段。
`每个进程使用完共享内存段后,要分离(detach)这个内存段。
`在某个地方,必须有一个进程来销毁这个内存段。

Linux的内存模型:
`每个进程的虚拟内存被分为页(page)。
`每个进程维护自己的内存地址到虚拟内存页之间的映射。
`实际的数据存在于进程的内存地址上。
`尽管每个进程有自己的地址空间,多个进程的映射还是可以指向相同的页。

所有的共享内存段的大小,都是Linux内存页大小的整数倍。
Linux的页大小是4KB,不过程序员应该使用getpagesize函数来获得这个值。

分配:shmget
`第一个参数是一个整型的键,用于指定要创建的段。无关的进程可以通过指定同一个键来访问同一段共享内存。
`使用常量IPC_PRIVATE作为第一个参数,可以避免键的冲突。
`第二个参数是分配的段的大小(字节数)。实际分配的字节数会舍弃多余部分到页大小的整数倍。
`第三个参数是位标志,用来表示创建的选项。
``IPC_CREATE:表明要创建新的共享内存空间。
``IPC_EXCL:总是和上一个标志一起使用。如果指定键的共享内存段已经存在,这个标志会导致调用失败;如果没有指定这个标志,调用会返回已经占用这个键的共享内存段。
``模式标志:9个bit的标志,和系统的文件权限使用相同的标志,不过执行标志无效。这些标志定义在<sys/stat.h>中。
`返回值是新创建的或者取得的内存段的标志符(SHMID)。

连接:shmat
`第一个参数是由shmget得到的标志符(SHMID)。
`第二个参数是指向你想要映射到的本进程的地址空间的指针。如果指定NULL,Linux负责选择一个可用的地址。


/*共享内存 打印各种不同类型的数据所存放的位置 */
#include <sys/shm.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>

#define ARRAY_SIZE 4000
#define MALLOC_SIZE 10000
#define SHM_SIZE 10000
#define SHM_MODE 0666 //设置读写权限

char array[ARRAY_SIZE];

main()
{
int shmid;
char *p,*shmp;

printf("array[] from %lx to %ls \n",(unsigned long)&array[0],(unsigned long)&array[ARRAY_SIZE] );
printf("stack around %lx \n",(unsigned long)&shmid);

if ((p = malloc(MALLOC_SIZE)) == NULL)
printf("malloc error! errno=%d\n",errno);
printf("malloced from %lx to %lx\n",(unsigned long)p,(unsigned long)p+MALLOC_SIZE);

if((shmid= shmget(IPC_PRIVATE,SHM_SIZE,SHM_MODE)) < 0){
if((shmid = shmget(IPC_PRIVATE,SHM_SIZE,IPC_CREAT|SHM_MODE)) < 0)
printf("creat shmget error! error=%d\n",errno);
exit(-1);
}

/*if((shmid = shmget(IPC_PRIVATE,SHM_SIZE,IPC_CREAT|SHM_MODE)) < 0)
printf("shmget error! errno=%d \n",errno);*/
if((shmp = shmat(shmid,0,0)) == (void*) -1)
printf("shmat error! errno=%d\n",errno);
printf("shared memory attached from %lx to %lx\n",(unsigned long)shmp,(unsigned long)shmp+SHM_SIZE);

if(shmctl(shmid,IPC_RMID,0) < 0)
printf("shmctl error! errno=%d\n",errno);

shmdt(shmp);
exit(0);
}

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页