Posix提供了无亲缘关系进程间共享内存区的两种方法:
1.内存映射文件
由open函数打开,由mmap函数把得到的描述字映射到当前进程地址空间的一个文件。
#include <sys/mman.h>
void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
addr可以指定为描述字fd应被映射到的进程内空间起始地址。通常被指定为NULL,由内核自己决定。len为映射的字节数。offset常设置为0,prot常见值为PROT_READ|PROT_WRITE。
prot常用参数表:
prot description
PROT_READ 数据可读
PROT_WRITE 数据可写
PROT_EXEC 数据可执行
PROT_NONE 数据不可访问
flags常用参数表:
flags description
MAP_SHARED 变动是共享的
MAP_PRIVATE 变动是私有的
MAP_FIXED 准确解释addr参数
父子进程之间共享内存区的方法之一是,父进程在调用fork前先指定MAP_SHARED调用mmap()。
int munmap(void *addr, size_t len);
4.4BSD提供了匿名内存映射,避免了文件的创建和打开。其办法是把mmap的flags参数指定成MAP_SHARED|MAP_ANON,fd指定为-1。offset参数被忽略。这样的内存被初始化为0。使用方式类似这样:
int *ptr = mmap(NULL, sizeof(int), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, -1, 0);
与需要打开文件的mmap相比,增加了MAP_ANON,fd = -1. offset值随意。
2.共享内存区对象
由shm_open打开一个Posix名字,所返回描述字由mmap函数映射到当前进程地址空间。
int shm_open(const char *name, int oflag, mode_t mode);
int shm_unlink(const char *name);
oflag参数必须或者含有O_RDONLY,或者O_RDWR标志,也可以指定O_CREAT、O_EXCL或O_TRUNC。如果随O_RDWR指定O_TRUNC,而且所需的共享内存区对象已经存在,那么它将被截短成0长度。一般shm_open的oflag与mmanp的第三个参数读写权限相对应。
mode参数总是必须指定。
处理mmap的时候,普通文件或共享内存区对象的大小都可以通过调用ftruncate修改。
#include <unistd.h>
int ftruncate(int fd, off_t length);
允许将普通文件和共享内存区对象的大小指定为比原来的大或小。
//file_shm.c
#include <semaphore.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/mman.h>
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
struct shared
{
sem_t mutex;
int count;
}shared;
int main(int argc, char **argv)
{
int fd, i, nloop;
struct shared *ptr;
if(argc != 3)
{
perror("usage: memshared <pathname> <#loops>");
exit(0);
}
nloop = atoi(argv[2]);
fd = open(argv[1], O_RDWR | O_CREAT, FILE_MODE);
write(fd, &shared, sizeof(struct shared));
// mmap returns void*
ptr = mmap(NULL, sizeof(struct shared), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
close(fd);
sem_init(&ptr->mutex, 1, 1);// 2nd param 1 means sem is shared among different processes
setbuf(stdout, NULL);
if(fork() == 0)
{
for(i = 0; i < nloop; i++)
{
sem_wait(&ptr->mutex);
printf("child:%d\n", ptr->count++);
sem_post(&ptr->mutex);
}
exit(0);
}
for(i = 0; i < nloop; i++)
{
sem_wait(&ptr->mutex);
printf("parent:%d\n", ptr->count++);
sem_post(&ptr->mutex);
}
sem_destroy(&ptr->mutex);
return 0;
}
// obj_shm.c
#include <semaphore.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/mman.h>
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
struct shared
{
sem_t mutex;
int count;
}shared;
int main(int argc, char **argv)
{
int fd, i, nloop;
struct shared *ptr;
if(argc != 2)
{
perror("usage: memshared <#loops>");
exit(0);
}
nloop = atoi(argv[1]);
// mmap returns void*
// BSD 4.4 provide a way of mmaping without opening a file, as follows
ptr = mmap(NULL, sizeof(struct shared), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
sem_init(&ptr->mutex, 1, 1);// 2nd param 1 means sem is shared among different processes
setbuf(stdout, NULL);
if(fork() == 0)
{
for(i = 0; i < nloop; i++)
{
sem_wait(&ptr->mutex);
printf("child:%d\n", ptr->count++);
sem_post(&ptr->mutex);
}
exit(0);
}
for(i = 0; i < nloop; i++)
{
sem_wait(&ptr->mutex);
printf("parent:%d\n", ptr->count++);
sem_post(&ptr->mutex);
}
sem_destroy(&ptr->mutex);
return 0;
}
共享内存区
最新推荐文章于 2018-10-13 16:48:00 发布