System V IPC综合实践

实践:实现一个先进先出的共享内存shmfifo

使用消息队列即可实现消息的先进先出(FIFO),但是使用共享内存实现消息的先进先出则更加快速;

我们首先完成C语言版本的shmfifo(基于过程调用),然后在此基础上实现C++版本的ShmFifo,将1块共享内存与3个信号量(1个mutext信号量,1个full信号量,1个empty信号量)封装成一个类ShmFifo,然后编写各自的测试代码;

shmfifo说明:

将申请到的共享内存作为一块缓冲区,将该内存的首部(p_shm到p_payload的内容)格式化为如上图所示的形式;

读/写进程不断的按照现金先出的原则从其中读出/写入数据,则读/写进程就可以看成生产者/消费者了,因此,使用信号量sem_mutex(初值为1)来互斥访问共享内存,使用sem_full(初值为共享缓冲区块数),sem_empty(初值为0)来同步两个进程.

C版本:

//结构体类型定义typedef struct shmhead shmhead_t;typedef struct shmfifo shmfifo_t;//共享内存首部定义struct shmhead{unsigned int blksize; //块大小unsigned int blocks; //总块数unsigned int rd_index; //读索引块unsigned int wr_index; //写索引块};//整个shmfifo句柄struct shmfifo{shmhead_t *p_shm; //共享内存头部指针char *p_payload; //有效负载其实地址int shmid;//共享内存IDint sem_mutex; //互斥信号量int sem_full; //满信号量int sem_empty; //空信号量};/**shmfifo初始化既包含了共享内存的初始化, 也包含了三个信号量的初始化;小技巧: 对一个IPC对象首先尝试打开, 如果打开失败, 则表示该IPC对象尚未创建, 则需要创建之, 而如果打开成功的话, 则进行其他操作**/shmfifo_t *shmfifo_init(int key, int blksize, int blocks){shmfifo_t *fifo = (shmfifo_t *)malloc(sizeof(shmfifo_t));assert(fifo != NULL);memset(fifo, 0, sizeof(shmfifo_t));// 尝试打开共享内存int shmid = shmget(key, 0, 0);// 如果打开失败, 则表示该共享内存尚未创建, 则创建if (shmid == -1){/** 设置共享内存 **/int size = blksize*blocks + sizeof(shmhead_t);//创建共享内存fifo->shmid = shmget(key, size, IPC_CREAT|0666);if (fifo->shmid == -1)err_exit("shmget error");//创建共享内存成功, 则需要将其连接到进程的地址空间//void *shmat(int shmid, const void *shmaddr, int shmflg);fifo->p_shm = (shmhead_t *)shmat(fifo->shmid, NULL, 0);if (fifo->p_shm == (void *) -1)err_exit("shmat error");//将共享内存的首部初始化为struct shmheadfifo->p_shm->blksize = blksize;fifo->p_shm->blocks = blocks;fifo->p_shm->rd_index = 0;fifo->p_shm->wr_index = 0;fifo->p_payload = (char *)(fifo->p_shm+1);/** 设置三个信号量 **/fifo->sem_mutex = sem_create(key);sem_setval(fifo->sem_mutex, 1);fifo->sem_full = sem_create(key+1);sem_setval(fifo->sem_full, 10);fifo->sem_empty = sem_create(key+2);sem_setval(fifo->sem_empty, 0);}else{fifo->shmid = shmid;//共享内存已经存在, 并且打开成功, 则需要将其连接到进程的地址空间fifo->p_shm = (shmhead_t *)shmat(fifo->shmid, NULL, 0);if (fifo->p_shm == (void *) -1)err_exit("shmat error");fifo->p_payload = (char *)(fifo->p_shm+1);/** 设置三个信号量 **/fifo->sem_mutex = sem_open(key);fifo->sem_full = sem_open(key+1);fifo->sem_empty = sem_open(key+2);}return fifo;}/**shmfifo的销毁既要销毁共享内存, 也要销毁三个信号量, 还需要将malloc出来的shmfifo_t结构体释放掉**/void shmfifo_destroy(shmfifo_t *fifo){//释放三个信号量sem_delete(fifo->sem_mutex);sem_delete(fifo->sem_full);sem_delete(fifo->sem_empty);//分离内存shmdt(fifo->p_shm);//删除共享内存if (shmctl(fifo->shmid, IPC_RMID, NULL) == -1)err_exit("remove share memory error");//将fifo内存释放free(fifo);}/**将buf内容按照顺序写入共享内存注意此处的P,V操作并没有使用SEM_UNDO标记**/void shmfifo_put(shmfifo_t *fifo, const void *buf){sem_P(fifo->sem_full);sem_P(fifo->sem_mutex);//从结构体中获取写入位置char *index = fifo->p_payload +(fifo->p_shm->wr_index * fifo->p_shm->blksize);memcpy(index, buf, fifo->p_shm->blksize);fifo->p_shm->wr_index = (fifo->p_shm->wr_index+1)%fifo->p_shm->blocks;sem_V(fifo->sem_mutex);sem_V(fifo->sem_empty);}/**将共享内存中的内容按照顺序读出到buf注意此处的P,V操作并没有使用SEM_UNDO标记**/void shmfifo_get(shmfifo_t *fifo, void *buf){sem_P(fifo->sem_empty);sem_P(fifo->sem_mutex);//从结构体中获取读出位置char *index = fifo->p_payload +(fifo->p_shm->rd_index * fifo->p_shm->blksize);memcpy(buf, index, fifo->p_shm->blksize);fifo->p_shm->rd_index = (fifo->p_shm->rd_index+1)%fifo->p_shm->blocks;sem_V(fifo->sem_mutex);sem_V(fifo->sem_full);}/**测试代码: write.cpp**/struct Student{char name[32];int age;};int main(){shmfifo_t *fifo = shmfifo_init(1234, sizeof(Student), 15);Student s;bzero(&s, sizeof(s));strcpy(s.name, "xiaofang");for (int i = 0; i < 15; ++i){sprintf(&(s.name[8]), "%d", i);s.age = i;shmfifo_put(fifo, &s);cout << "put success" << endl;}}/**测试代码: read.cpp**/int main(){shmfifo_t *fifo = shmfifo_init(1234, sizeof(Student), 3);Student s;for (int i = 0; i < 5; ++i){bzero(&s, sizeof(s));shmfifo_get(fifo, &s);printf("name: %s, age = %d\n", s.name, s.age);}return 0;}/**测试代码: 销毁所创建的共享内存与信号量, free**/int main(){shmfifo_t *fifo = shmfifo_init(1234, sizeof(Student), 3);shmfifo_destroy(fifo);return 0;}

完整C源代码:

渐渐少了联络,友谊就变的淡了,所以,抽点时间,联络朋友一起聊聊天,

System V IPC综合实践

相关文章:

你感兴趣的文章:

标签云: