1、共享内存
1)分类
XSI 共享内存
匿名共享内存mmap
2)原理:
地址空间:一个连续的内存地址单元
物理地址空间:物理内存地址组成的地址空间,其空间大小与物理内存一致。
虚拟地址空间:CPU MMU 提供的功能,可将虚地址转换为物理地址,所有的虚地址组成的连续空间叫虚地址空间,有时候也叫线性空间。其空间大小与机器字长相关。32位机器上为2^32,4G左右
3)特性:
内核相关的;需要与同步原语一起使用才能保证数据一致性(Mutex,读写锁、信号量);最快速,copy较少
4)API
int shmget(key_t key, size_t size, int shmflg);
得到一个共享内存标识符或创建一个共享内存对象并返回共享内存标识符
void* shmat(int shmid, const void* shmaddr, int shmflg);
连接共享内存标识符为shmid的共享内存,连接成功后把共享内存区对象映射到调用进程的地址空间,随后可像本地空间一样访问
int shmdt(const void* shmaddr);
与shmat函数相反,是用来断开与共享内存附加点的地址,禁止本进程访问此片共享内存
int shmctl(int shmid, int cmd, struct shmid_ds* buf);
完成对共享内存的控制
5)示例代码
示例1:父子进程通信
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <error.h>
#define SIZE 1024
int main()
{
int shmid;
char *shmaddr;
struct shmid_ds buf;
int flag = 0;
int pid;
shmid = shmget(IPC_PRIVATE, SIZE, IPC_CREAT|0600);
if (shmid < 0)
{
perror("get shm ipc_id error");
return -1;
}
pid = fork();
if(pid == 0)
{
//child
shmaddr = (char*)shmat(shmid, NULL, 0);
if ((int)shmaddr == -1)
{
perror("shmat addr error");
return -1;
}
strcpy(shmaddr, "Hi, I am child process!\n");
shmdt(shmaddr);
return 0;
}
else if (pid > 0)
{
//parent
sleep(3);
flag = shmctl(shmid, IPC_STAT, &buf);
if (flag == -1)
{
perror("shmctl shm error");
return -1 ;
}
printf("shm_segsz =%d bytes\n", buf.shm_segsz);
printf("parent pid=%d, shm_cpid = %d \n", getpid(), buf.shm_cpid); //p_pid
printf("chlid pid=%d, shm_lpid = %d \n", pid ,buf.shm_lpid); //c_pid
shmaddr = (char *)shmat(shmid, NULL, 0);
if ((int)shmaddr == -1)
{
perror("shmat addr error") ;
return -1 ;
}
printf("%s", shmaddr);
shmdt(shmaddr );
shmctl(shmid, IPC_RMID, NULL);
}
else
{
perror("fork error") ;
shmctl(shmid, IPC_RMID, NULL);
}
return 0 ;
}
示例2:多进程读写,一个读,一个写
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
typedef struct
{
char name[8];
int age;
} people;
int main(int argc, char** argv)
{
int shm_id, i;
key_t key;
char temp[8];
memset(temp, 0, 8);
people *p_map;
char pathname[30];
memset(pathname, 0, 30);
strcpy(pathname, "/tmp");
key = ftok(pathname, 0x03);
if(key == -1)
{
perror("ftok error");
return -1;
}
printf("key = %d\n", key) ;
shm_id = shmget(key, 4096, IPC_CREAT | IPC_EXCL | 0600);
if(shm_id ==- 1)
{
perror("shmget error");
return -1;
}
printf("shm_id = %d\n", shm_id) ;
p_map =(people*)shmat(shm_id, NULL, 0);
memset(temp, 0x00, sizeof(temp));
strcpy(temp, "test") ;
temp[4] = '0';
for(i = 0; i < 3; i++)
{
temp[4] += 1;
strncpy((p_map+i)->name, temp, 5);
(p_map+i)->age =0 + i;
}
shmdt(p_map);
return 0 ;
}
#include <stdio.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h>
typedef struct
{
char name[8];
int age;
} people;
int main(int argc, char** argv)
{
int shm_id, i;
key_t key;
people *p_map;
char pathname[30];
memset(pathname, 0, 30);
strcpy(pathname, "/tmp") ;
key = ftok(pathname, 0x03);
if(key == -1)
{
perror("ftok error");
return -1;
}
printf("key= %d\n", key) ;
shm_id = shmget(key, 0, 0); //obatain the exist shm
if(shm_id == -1)
{
perror("shmget error");
return -1;
}
printf("shm_id= %d\n", shm_id) ;
p_map = (people*)shmat(shm_id, NULL, 0);
for(i = 0; i < 3; i++)
{
printf( "name: %s\n",(*(p_map+i)).name );
printf( "age: %d\n",(*(p_map+i)).age );
}
if(shmdt(p_map) == -1)
{
perror("detach error");
return -1;
}
return 0 ;
}
使用ipcrm -m shm_id删除此共享内存
参考
【1】 http://www.cnblogs.com/mydomain/archive/2011/06/23/2088339.html