用几个小程序简单总结一下UNPv2讲的三种内存共享的方法。
一、内存映射文件
(1)内存映射文件(可用在无亲缘关系的进程间共享)
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
-
#define FILE_MODE (S_IRWXU | S_IRWXG | S_IRWXO)
-
#define IPC_FILE "/tmp/temp.1"
-
-
int main(int argc, char **argv)
-
{
-
int fd = -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);
-
-
-
-
setbuf(stdout, NULL);
-
-
if (fork() == 0)
-
{
-
for (i = 0; i < nloop; i++)
-
{
-
sem_wait(&mutex);
-
printf("child: %d\n", (*ptr)++);
-
sem_post(&mutex);
-
}
-
-
return 0;
-
}
-
-
for (i = 0; i < nloop; i++)
-
{
-
sem_wait(&mutex);
-
printf("parent: %d\n", (*ptr)++);
-
sem_post(&mutex);
-
}
-
-
return 0;
-
}
(2)匿名内存映射(用于有亲缘关系的进程间共享。flags:MAP_SHARED | MAP_ANONYMOUS 或 /dev/zero设备,以MAP_ANONYMOUS为例)
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
-
int main(int argc, char **argv)
-
{
-
int i, 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);
-
-
-
-
-
setbuf(stdout, NULL);
-
-
if (fork() == 0)
-
{
-
for (i = 0; i < nloop; i++)
-
{
-
sem_wait(&mutex);
-
printf("child: %d\n", (*ptr)++);
-
sem_post(&mutex);
-
}
-
-
return 0;
-
}
-
-
for (i = 0; i < nloop; i++)
-
{
-
sem_wait(&mutex);
-
printf("parent: %d\n", (*ptr)++);
-
sem_post(&mutex);
-
}
-
-
return 0;
-
}
二、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"
-
typedef struct
-
{
-
int count;
-
}SHM_STRUCT;
-
-
sem_t *mutex;
-
-
int main(int argc, char **argv)
-
{
-
int fd;
-
SHM_STRUCT *ptr;
-
-
shm_unlink(SH_NAME);
-
fd = shm_open(SH_NAME, O_RDWR | O_CREAT | O_EXCL, FILE_MODE);
-
if (fd < 0)
-
{
-
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);
-
-
return 0;
-
}
(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"
-
-
typedef struct
-
{
-
int count;
-
}SHM_STRUCT;
-
-
sem_t *mutex;
-
-
int main(int argc, char **argv)
-
{
-
int fd, i, nloop;
-
pid_t pid;
-
SHM_STRUCT *ptr;
-
-
nloop = atoi(LOOP_NUM);
-
-
fd = shm_open(SH_NAME, O_RDWR, FILE_MODE);
-
if (fd < 0)
-
{
-
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 < nloop; i++)
-
{
-
sem_wait(mutex);
-
printf("pid %ld: %d\n", (long)pid, ptr->count++);
-
sem_post(mutex);
-
}
-
-
return 0;
-
}
(3)client退出后,共享内存区对象还是存在于系统中的,如果不删除,则之后运行client后,共享内存区里的count变量会不断累加。可以用shm_unlink()和sem_unlink()删除共享内存区对象和有名信号量。
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
-
int main(int argc, char **argv)
-
{
-
if (argc != 3)
-
{
-
printf("error command!\n");
-
return -1;
-
}
-
-
shm_unlink(argv[1]);
-
sem_unlink(argv[2]);
-
-
return 0;
-
}
三、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))
-
-
int createShm(key_t key, size_t size);
-
void *attachShm(key_t key);
-
int dettachShm(const void *shmaddr);
-
int destroyShm(key_t key);
-
int setShmParam(key_t key, struct shmid_ds *buff);
-
int getShmParam(key_t key, struct shmid_ds *buff);
-
-
#endif
(2)shmOpt.c
-
#include
-
#include "shmOpt.h"
-
-
int createShm(key_t key, size_t size)
-
{
-
int oflag = SVSHM_MODE | IPC_CREAT;
-
int id = shmget(key, size, oflag);
-
-
if (id < 0)
-
{
-
printf("%s:create shared memory error!\n", __FUNCTION__);
-
}
-
-
return id;
-
}
-
-
void *attachShm(key_t key)
-
{
-
int oflag = SVSHM_MODE | IPC_CREAT;
-
int id;
-
char *ptr;
-
-
id = shmget(key, 0, oflag);
-
if (id < 0)
-
{
-
printf("%s:get shared memory error!\n", __FUNCTION__);
-
return NULL;
-
}
-
-
ptr = shmat(id, NULL, 0);
-
if (*ptr == -1)
-
{
-
printf("%s:attach shared memory error!\n", __FUNCTION__);
-
return NULL;
-
}
-
-
return ptr;
-
}
-
-
int dettachShm(const void *shmaddr)
-
{
-
return shmdt(shmaddr);
-
}
-
-
int destroyShm(key_t key)
-
{
-
int id;
-
int oflag = SVSHM_MODE | IPC_CREAT;
-
int ret;
-
-
id = shmget(key, 0, oflag);
-
if (id < 0)
-
{
-
printf("%s:get shared memory error!\n", __FUNCTION__);
-
return -1;
-
}
-
-
ret = shmctl(id, IPC_RMID, NULL);
-
if (ret < 0)
-
{
-
printf("%s:delete shared memory error!\n", __FUNCTION__);
-
return -1;
-
}
-
-
return 0;
-
}
-
-
int setShmParam(key_t key, struct shmid_ds *buff)
-
{
-
int id;
-
int oflag = SVSHM_MODE | IPC_CREAT;
-
int ret;
-
-
id = shmget(key, 0, oflag);
-
if (id < 0)
-
{
-
printf("%s:get shared memory error!\n", __FUNCTION__);
-
return -1;
-
}
-
-
ret = shmctl(id, IPC_SET, buff);
-
if (ret < 0)
-
{
-
printf("%s:set parameters error!\n", __FUNCTION__);
-
return -1;
-
}
-
-
return 0;
-
}
-
-
int getShmParam(key_t key, struct shmid_ds *buff)
-
{
-
int id;
-
int oflag = SVSHM_MODE | IPC_CREAT;
-
int ret;
-
-
id = shmget(key, 0, oflag);
-
if (id < 0)
-
{
-
printf("%s:get shared memory error!\n", __FUNCTION__);
-
return -1;
-
}
-
-
ret = shmctl(id, IPC_STAT, buff);
-
if (ret < 0)
-
{
-
printf("%s:get parameters error!\n", __FUNCTION__);
-
return -1;
-
}
-
-
return 0;
-
}
-
以下是例子程序。由于没有同步保护,因此首先先用server创建共享内存区,然后再多次调用client看count变量是否能持续累加即可,最后由shmRemove删除共享内存区。
(1)server.c
-
#include
-
#include "shmOpt.h"
-
-
typedef struct
-
{
-
int count;
-
}SHM_STRUCT;
-
-
int main()
-
{
-
int id;
-
-
id = createShm(SHM_KEY, sizeof(SHM_STRUCT));
-
-
if (id < 0)
-
{
-
printf("createShm error!\n");
-
return -1;
-
}
-
-
return 0;
-
}
(2)client.c
-
#include
-
#include "shmOpt.h"
-
-
#define LOOP_NUM 1000
-
-
typedef struct
-
{
-
int count;
-
}SHM_STRUCT;
-
-
int main()
-
{
-
SHM_STRUCT *ptr;
-
struct shmid_ds buff;
-
int i;
-
-
ptr = attachShm(SHM_KEY);
-
-
if (!ptr)
-
{
-
printf("cannot attach shm!\n");
-
return -1;
-
}
-
-
for (i = 0; i < LOOP_NUM; i++)
-
{
-
ptr->count++;
-
}
-
-
printf("ptr->count=%d\n", ptr->count);
-
-
printf("======================\n");
-
-
if (getShmParam(SHM_KEY, &buff) < 0)
-
{
-
printf("get shmParam error!\n");
-
return -1;
-
}
-
-
printf("shm size:%d--sizeof(SHM_STRUCT):%d\n", buff.shm_segsz, sizeof(SHM_STRUCT));
-
-
return 0;
-
}
(3)shmRemove.c
-
#include
-
#include "shmOpt.h"
-
-
int main()
-
{
-
destroyShm(SHM_KEY);
-
return 0;
-
}
阅读(2031) | 评论(0) | 转发(0) |