用几个小程序简单总结一下UNPv2讲的三种内存共享的方法。
一、内存映射文件
(1)内存映射文件(可用在无亲缘关系的进程间共享)
#include
#include
#include
#include
#include
#include
#include
#define FILE_MODE (S_IRWXU | S_IRWXG | S_IRWXO)
#define IPC_FILE "/tmp/temp.1"
intmain(intargc,char**argv)
{
intfd = -1, i, nloop, zero = 0;
int*ptr;
sem_t mutex;
if(argc != 2)
{
printf("usage: incr \n");
return-1;
}
nloop = atoi(argv[1]);
fd = open(IPC_FILE, O_RDWR | O_CREAT, FILE_MODE);
if(-1 == fd)
{
printf("open %s error!\n", IPC_FILE);
return-1;
}
write(fd, &zero, sizeof(int));
ptr = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
close(fd);
//sem_init(&mutex, 1, 1);//有误,无名信号量需位于共享内存才可在进程间共享
setbuf(stdout, NULL);
if(fork() == 0)
{
for(i = 0; i
{
sem_wait(&mutex);
printf("child: %d\n", (*ptr)++);
sem_post(&mutex);
}
return0;
}
for(i = 0; i
{
sem_wait(&mutex);
printf("parent: %d\n", (*ptr)++);
sem_post(&mutex);
}
return0;
}
(2)匿名内存映射(用于有亲缘关系的进程间共享。flags:MAP_SHARED | MAP_ANONYMOUS 或 /dev/zero设备,以MAP_ANONYMOUS为例)
#include
#include
#include
#include
#include
#include
#include
intmain(intargc,char**argv)
{
inti, nloop;
int*ptr;
sem_t mutex;
if(argc != 2)
{
printf("usage: incr_anonymous \n");
return-1;
}
nloop = atoi(argv[1]);
ptr = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);/* 匿名映射的内存区被初始化为0 */
//sem_init(&mutex, 1, 1);//有误,无名信号量需位于共享内存才可在进程间共享
setbuf(stdout, NULL);
if(fork() == 0)
{
for(i = 0; i
{
sem_wait(&mutex);
printf("child: %d\n", (*ptr)++);
sem_post(&mutex);
}
return0;
}
for(i = 0; i
{
sem_wait(&mutex);
printf("parent: %d\n", (*ptr)++);
sem_post(&mutex);
}
return0;
}
二、Posix共享内存区对象
(1)server.c创建共享内存区和有名信号量,并退出,posix共享内存区和有名信号量并不会因为server退出而被删,除非被显式删除。创建共享内存区对象和有名信号量的文件在/dev/shm中。
#include
#include
#include
#include
#include
#include
#include
#define FILE_MODE (S_IRWXU | S_IRWXG | S_IRWXO)
#define SH_NAME "shm1"
#define SEM_NAME "sem1"
typedefstruct
{
intcount;
}SHM_STRUCT;
sem_t *mutex;
intmain(intargc,char**argv)
{
intfd;
SHM_STRUCT *ptr;
shm_unlink(SH_NAME);
fd = shm_open(SH_NAME, O_RDWR | O_CREAT | O_EXCL, FILE_MODE);
if(fd
{
printf("create shared memory error!\n");
return-1;
}
ftruncate(fd, sizeof(SHM_STRUCT));
ptr = mmap(NULL, sizeof(SHM_STRUCT), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
close(fd);
sem_unlink(SEM_NAME);
mutex = sem_open(SEM_NAME, O_CREAT | O_EXCL, FILE_MODE, 1);
if(mutex == NULL)
{
printf("create semaphore error!\n");
return-1;
}
sem_close(mutex);
return0;
}
(2)client.c打开共享内存区,并对count进行累加。
#include
#include
#include
#include
#include
#include
#include
#define FILE_MODE (S_IRWXU | S_IRWXG | S_IRWXO)
#define SH_NAME "shm1"
#define SEM_NAME "sem1"
#define LOOP_NUM "10000"
typedefstruct
{
intcount;
}SHM_STRUCT;
sem_t *mutex;
intmain(intargc,char**argv)
{
intfd, i, nloop;
pid_t pid;
SHM_STRUCT *ptr;
nloop = atoi(LOOP_NUM);
fd = shm_open(SH_NAME, O_RDWR, FILE_MODE);
if(fd
{
printf("open share memory error!\n");
return-1;
}
ptr = mmap(NULL, sizeof(SHM_STRUCT), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
close(fd);
mutex = sem_open(SEM_NAME, 0);
if(mutex == NULL)
{
printf("open semaphore error!\n");
return-1;
}
pid = getpid();
for(i = 0; i
{
sem_wait(mutex);
printf("pid %ld: %d\n", (long)pid, ptr->count++);
sem_post(mutex);
}
return0;
}
(3)client退出后,共享内存区对象还是存在于系统中的,如果不删除,则之后运行client后,共享内存区里的count变量会不断累加。可以用shm_unlink()和sem_unlink()删除共享内存区对象和有名信号量。
#include
#include
#include
#include
#include
#include
#include
intmain(intargc,char**argv)
{
if(argc != 3)
{
printf("error command!\n");
return-1;
}
shm_unlink(argv[1]);
sem_unlink(argv[2]);
return0;
}
三、system V共享内存区
虽然现在glibc都支持posix共享内存,但在使用uclibc的嵌入式环境中则是不一定的,还需要用到system v接口。这里先只给出system v共享内存的例子,而system v信号量则留待下一篇写。
首先,封装一下几个接口。
(1)shmOpt.h
#ifndef __SHMOPT_H__
#define __SHMOPT_H__
#include
#define SHM_KEY 1234
#define SVSHM_MODE ((SHM_R) | (SHM_W) | (SHM_R >> 3) | (SHM_R >> 6))
intcreateShm(key_t key,size_tsize);/* 创建共享内存区 */
void*attachShm(key_t key);/* 连接共享内存区 */
intdettachShm(constvoid*shmaddr);/* 断接共享内存区 */
intdestroyShm(key_t key);/* 删除共享内存区 */
intsetShmParam(key_t key,structshmid_ds *buff);/* 设置共享内存区参数 */
intgetShmParam(key_t key,structshmid_ds *buff);/* 获取共享内存区参数 */
#endif
(2)shmOpt.c
#include
#include "shmOpt.h"
intcreateShm(key_t key,size_tsize)
{
intoflag = SVSHM_MODE | IPC_CREAT;
intid = shmget(key, size, oflag);
if(id
{
printf("%s:create shared memory error!\n", __FUNCTION__);
}
returnid;
}
void*attachShm(key_t key)/* fail:NULL */
{
intoflag = SVSHM_MODE | IPC_CREAT;
intid;
char*ptr;
id = shmget(key, 0, oflag);
if(id
{
printf("%s:get shared memory error!\n", __FUNCTION__);
returnNULL;
}
ptr = shmat(id, NULL, 0);
if(*ptr == -1)
{
printf("%s:attach shared memory error!\n", __FUNCTION__);
returnNULL;
}
returnptr;
}
intdettachShm(constvoid*shmaddr)
{
returnshmdt(shmaddr);
}
intdestroyShm(key_t key)
{
intid;
intoflag = SVSHM_MODE | IPC_CREAT;
intret;
id = shmget(key, 0, oflag);
if(id
{
printf("%s:get shared memory error!\n", __FUNCTION__);
return-1;
}
ret = shmctl(id, IPC_RMID, NULL);
if(ret
{
printf("%s:delete shared memory error!\n", __FUNCTION__);
return-1;
}
return0;
}
intsetShmParam(key_t key,structshmid_ds *buff)
{
intid;
intoflag = SVSHM_MODE | IPC_CREAT;
intret;
id = shmget(key, 0, oflag);
if(id
{
printf("%s:get shared memory error!\n", __FUNCTION__);
return-1;
}
ret = shmctl(id, IPC_SET, buff);
if(ret
{
printf("%s:set parameters error!\n", __FUNCTION__);
return-1;
}
return0;
}
intgetShmParam(key_t key,structshmid_ds *buff)
{
intid;
intoflag = SVSHM_MODE | IPC_CREAT;
intret;
id = shmget(key, 0, oflag);
if(id
{
printf("%s:get shared memory error!\n", __FUNCTION__);
return-1;
}
ret = shmctl(id, IPC_STAT, buff);
if(ret
{
printf("%s:get parameters error!\n", __FUNCTION__);
return-1;
}
return0;
}
以下是例子程序。由于没有同步保护,因此首先先用server创建共享内存区,然后再多次调用client看count变量是否能持续累加即可,最后由shmRemove删除共享内存区。
(1)server.c
#include
#include "shmOpt.h"
typedefstruct
{
intcount;
}SHM_STRUCT;
intmain()
{
intid;
id = createShm(SHM_KEY, sizeof(SHM_STRUCT));
if(id
{
printf("createShm error!\n");
return-1;
}
return0;
}
(2)client.c
#include
#include "shmOpt.h"
#define LOOP_NUM 1000
typedefstruct
{
intcount;
}SHM_STRUCT;
intmain()
{
SHM_STRUCT *ptr;
structshmid_ds buff;
inti;
ptr = attachShm(SHM_KEY);
if(!ptr)
{
printf("cannot attach shm!\n");
return-1;
}
for(i = 0; i
{
ptr->count++;
}
printf("ptr->count=%d\n", ptr->count);
printf("======================\n");
if(getShmParam(SHM_KEY, &buff)
{
printf("get shmParam error!\n");
return-1;
}
printf("shm size:%d--sizeof(SHM_STRUCT):%d\n", buff.shm_segsz,sizeof(SHM_STRUCT));
return0;
}
(3)shmRemove.c
#include
#include "shmOpt.h"
intmain()
{
destroyShm(SHM_KEY);
return0;
}