关于Posix共享内存
2015-08-03 17:12
183 查看
Posix提供了两种在无亲缘关系的进程间共享内存区的方法:
1. 内存映射文件
由open函数打开, 由mmap函数把得到的描述符映射到当前进程的地址空间的一个文件
2. 共享内存区对象
由shm_open打开一个Posix IPC名字, mmap将得到的描述符映射到当前进程的地址空间
两者的差距在于获取描述符的手段不同
操作函数:
int shm_open(const char *name, int oflag, mode_t mode);
shm_open与sem_open, mq_open不同的地方在于, mode总是要指定的. 如果没有指定O_CREAT, 那么mode可以是0
int shm_unlink(const char *name);
shm_unlink与其他unlink函数一样, 直到全部引用关闭才删除. 其中一个作用是防止后续的open调用成功
以下给出使用的实例:
接下来, 就看一下程序的运行结果:
1. 内存映射文件
由open函数打开, 由mmap函数把得到的描述符映射到当前进程的地址空间的一个文件
2. 共享内存区对象
由shm_open打开一个Posix IPC名字, mmap将得到的描述符映射到当前进程的地址空间
两者的差距在于获取描述符的手段不同
操作函数:
int shm_open(const char *name, int oflag, mode_t mode);
shm_open与sem_open, mq_open不同的地方在于, mode总是要指定的. 如果没有指定O_CREAT, 那么mode可以是0
int shm_unlink(const char *name);
shm_unlink与其他unlink函数一样, 直到全部引用关闭才删除. 其中一个作用是防止后续的open调用成功
以下给出使用的实例:
//头文件 #include <stdio.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h> #include <semaphore.h> #include <sys/mman.h> #include <string.h> #include <errno.h> #include <sys/stat.h> /* For mode constants */ #include <fcntl.h> /* For O_* constants */ #define MESGSIZE 256 //every message's max size #define NMESG 16 //total max size struct shm_ds{ sem_t ds_mutex; sem_t ds_nempty; sem_t ds_nstored; int ds_nput; long ds_noverflow; //如果有客户没有空间再存放进共享内存, 那么这个变量加一. 该客户不再等待 sem_t ds_overflowmutex; //这变量也是共享的, 需要加锁 long ds_msgoff[NMESG]; //每个消息的起始位置 char ds_msgbuf[NMESG * MESGSIZE]; //所有消息的占有空间 };
//服务端代码 #include "scpm.h" int main(int ac, char *av[]) { int fd, index; int over_flows, offset, temp; struct shm_ds *ptr; if(ac != 2){ fprintf(stderr, "Usage server <pathname>"); exit(-1); } shm_unlink(av[1]); //保证我们创建的共享内存是新的 fd = shm_open(av[1], O_RDWR | O_CREAT | O_EXCL, (S_IRUSR | S_IWUSR | S_IROTH | S_IWOTH)); if(fd < 0){ perror("shm_open error:"); exit(-1); } ftruncate(fd, sizeof(struct shm_ds)); //调整对象的大小 ptr = mmap(NULL, sizeof(struct shm_ds), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if(ptr == MAP_FAILED){ perror("mmap error"); exit(-1); } close(fd); for(index=0; index<NMESG; index++) //初始化每个消息的起始位置, 为了方便以后使用 ptr->ds_msgoff[index] = index * MESGSIZE; sem_init(&ptr->ds_mutex, 1, 1); //每个共享变量都是shared的 sem_init(&ptr->ds_nempty, 1, NMESG); sem_init(&ptr->ds_nstored, 1, 0); sem_init(&ptr->ds_overflowmutex, 1, 1); index = 0; over_flows = 0; for(;;) //下面即为多个生产者一个消费者的模型 { sem_wait(&ptr->ds_nstored); sem_wait(&ptr->ds_mutex); offset = ptr->ds_msgoff[index]; printf("Index : %d . Content is [%s]\n", index, &ptr->ds_msgbuf[offset]); if(++index >= NMESG) index = 0; sem_post(&ptr->ds_mutex); sem_post(&ptr->ds_nempty); sem_wait(&ptr->ds_overflowmutex); temp = ptr->ds_noverflow; sem_post(&ptr->ds_overflowmutex); if(temp != over_flows) //因为没有位置而被放弃的客户个数,发生变化则输出告知 { printf("now %d are abandoned\n", temp); over_flows = temp; } } return 0; }
//客户端代码 #include "scpm.h" int main(int ac, char *av[]) { int loops, nusec; int fd, index, offset; pid_t pid; struct shm_ds *ptr; char buf[MESGSIZE]; if(ac != 4){ fprintf(stderr, "Usage : cspm <pathname> loops usec\n"); exit(-1); } loops = atoi(av[2]); nusec = atoi(av[3]); fd = shm_open(av[1], O_RDWR, 0); ptr = mmap(NULL, sizeof(struct shm_ds), PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0); close(fd); pid = getpid(); //这里我们让一个客户端多次输出, 模拟多个客户端的情况 for(index = 0; index < loops; index++) { usleep(nusec); snprintf(buf, MESGSIZE, "pid : %ld : message : %d", pid, index); //消息内容 //这里我们使用trywait的原因是某些客户端比如HTTP不会愿意等待, 如果没有消息存放位置则选择直接返回 if(sem_trywait(&ptr->ds_nempty) == -1){ if(errno == EAGAIN){ sem_wait(&ptr->ds_overflowmutex); ptr->ds_noverflow ++; sem_post(&ptr->ds_overflowmutex); continue; } else{ perror("sem_trywait error"); exit(-1); } } sem_wait(&ptr->ds_mutex); offset = ptr->ds_msgoff[ptr->ds_nput]; if(++(ptr->ds_nput) >= NMESG) ptr->ds_nput = 0; sem_post(&ptr->ds_mutex); //这里我们让互斥锁之间的critical code尽量的少, 以免互斥锁会影响性能 strcpy(&ptr->ds_msgbuf[offset], buf); sem_post(&ptr->ds_nstored); } return 0; }
接下来, 就看一下程序的运行结果:
$ gcc -o scpm server_clients_posix_mmap.c -lrt //服务端 $ gcc -o cspm clients_server_posix_mmap.c -lrt //客户端 $ ./scpm /haha & $ ./cspm /haha 5 0 $ ./scpm /haha Index : 0 . Content is [pid : 5911 : message : 0] //下面即为后台服务器的输出 Index : 1 . Content is [pid : 5911 : message : 1] Index : 2 . Content is [pid : 5911 : message : 2] Index : 3 . Content is [pid : 5911 : message : 3] Index : 4 . Content is [pid : 5911 : message : 4] ^C接下来不会再介绍System V的共享内存, 因为两者相差无几, 只是调用的函数换了换
相关文章推荐
- 安卓实习第十四天
- UVA 11572 Unique snowflakes (滑窗)
- eMMC(KLM8G2FE3B)
- python读取xml文件
- influxdb的核心概念
- Android的Touch事件分发机制,看完这个就够了
- java使用webscoket小李子
- python读取xml文件
- 基本数据类型 进制转换
- jQuery实现禁用鼠标右键
- 了解运行kafka&&zookeeper(一)
- 使用<shap>为Button加上阴影效果
- 解决服务器存在大量time_wait的问题
- 通过supervisor 管理服务
- Java网络编程(二)
- LInux内核同步与互斥
- Oracle如何&操作进行二进制的比对
- Android中View属性大全
- vim 配置
- 【Android应用开发技术:媒体开发】录像