linux共享内存和windows的共享内存逻辑上有很大区别,要注意一下几点
1. shmget的第三个参数标识
标识 | 描述 |
---|---|
IPC_EXCL | 这个加入后,如果已经存在标识为key的共享内存则报错返回-1 |
0 | 如果是0 的话,就可以实现,如果共享内存不存在则返回失败-1,否则直接创建返回成功 |
0666 | 这个标识符很多人不知道啥意思,其实试试就知道了,它可以让你在普通用户下创建访问共享内存,如果没有这个标识,共享内存的创建和访问都必须在root用户下进行,参考《unix环境高级编程第二版》,里面有 #define SHM_MODE 0600 /* user read/write */ |
2. 共享内存的回收
共享内存想完全销毁,需要满足两个条件
- 应用计数为0,
shmat/shmdt
- 标记为删除,
shmctl
如果引用计数不为0,你删除了,那么这个共享内存还在,还可以读取里面的值,但是共享内存的标记已经删除,所以后续程序无法打开,找不到共享内存
如果引用计数为0,但是你没标记删除,那么共享内存标记和空间都还在,可以访问并读取内存,造成内存泄露,注意了
3. 例子
首先是创建共享内存
/*
File: sharemem.c
Author: magicdmer
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main()
{
void *shm_addr = NULL;
int shmid;
key_t key;
key=ftok("/usr/local/ve-viewer",10);
if(key==-1)
{
perror("ftok error
");
return 0;
}
perror("shmid:%u
",key);
/*
这里要注意了,IPC_EXCL这个的作用是:如果存在这个共享内存了就返回失败
如果不加这个,会一直成功,会直接打开已有的
*/
shmid = shmget(key,1,IPC_CREAT|IPC_EXCL);
if (shmid == -1)
{
perror("shmget error
");
return 0;
}
shm_addr = shmat(shmid, NULL, 0);
if (shm_addr == -1)
{
perror("shmat error
");
return 0;
}
memcpy(shm_addr,"Y",1);
getchar();
if (shmdt(shm_addr) == -1)
{
perror("shmdt error
");
return 0;
}
if (shmctl(shmid, IPC_RMID, 0) == -1)
{
perror("shmctl error!
");
return 0;
}
return 0;
}
然后是读写共享内存
/*
File: sharemem.c
Author: magicdmer
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main()
{
void *shm_addr = NULL;
int shmid;
key_t key;
key=ftok("/usr/local/ve-viewer",10);
if(key==-1)
{
perror("ftok error
");
return 0;
}
//这里要注意了,最后一个flag设置成0,这样,如果共享内存不存在就会报错,不然即使没有也直接创建了
shmid = shmget(key,1,0);
if (shmid == -1)
{
perror("shmget error
");
return 0;
}
shm_addr = shmat(shmid, NULL, 0);
if (shm_addr == (void *)-1)
{
perror("shmat error!");
return 0;
}
char tmp[10];
bzero(tmp, 10);
memcpy(tmp,shm_addr,1);
printf("read from shared memory:%s
",tmp);
getchar();
bzero(tmp, 10);
memcpy(tmp,shm_addr,1);
printf("read from shared memory:%s
",tmp);
if (shmdt(shm_addr) == -1)
{
perror("shmdt error
");
return 0;
}
}