用信号量解决生产者、消费者问题

实现shmfifo

ip.h

  1. #ifndef _IPC_H
  2. #define _IPC_H
  3. #include <unistd.h>
  4. #include <sys/types.h>
  5. #include <stdlib.h>
  6. #include <stdio.h>
  7. #include <errno.h>
  8. #include <string.h>
  9. #include <sys/types.h>
  10. #include <sys/wait.h>
  11. #include <sys/ipc.h>
  12. #include <sys/sem.h>
  13. union semun {
  14. int val; /* Value for SETVAL */
  15. struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
  16. unsigned short *array; /* Array for GETALL, SETALL */
  17. struct seminfo *__buf; /* Buffer for IPC_INFO
  18. (Linux-specific) */
  19. };
  20. #define ERR_EXIT(m) \
  21. do \
  22. { \
  23. perror(m); \
  24. exit(EXIT_FAILURE); \
  25. } while (0)
  26. int sem_create(key_t key);
  27. int sem_del(int semid);
  28. int sem_open(key_t key);
  29. int sem_setval(int semid, int val);
  30. int sem_getval(int semid, int val);
  31. int sem_p(int semid);
  32. int sem_v(int semid);
  33. #endif // !_IPC_H

ip.c

  1. #include "ipc.h"
  2. int sem_create(key_t key)
  3. {
  4. int semid;
  5. semid = semget(key, 1, IPC_CREAT|IPC_EXCL| 0666);
  6. if(semid == -1)
  7. ERR_EXIT("semget");
  8. return semid;
  9. }
  10. int sem_open(key_t key)
  11. {
  12. int semid;
  13. semid = semget(key, 0, 0);
  14. if(semid == -1)
  15. ERR_EXIT("semget");
  16. return semid;
  17. }
  18. int sem_setval(int semid, int val)
  19. {
  20. union semun su;
  21. su.val = val;
  22. int ret;
  23. ret = semctl(semid, 0, SETVAL, su);
  24. if(ret == -1)
  25. ERR_EXIT("semctl");
  26. return 0;
  27. }
  28. int sem_del(int semid)
  29. {
  30. int ret;
  31. ret = semctl(semid, 0, IPC_RMID, 0);
  32. if(ret == -1)
  33. ERR_EXIT("semctl");
  34. return 0;
  35. }
  36. int sem_getval(int semid, int val)
  37. {
  38. int ret;
  39. ret = semctl(semid, 0, GETVAL, 0);
  40. if(ret == -1)
  41. ERR_EXIT("semctl getval");
  42. return ret;
  43. }
  44. int sem_p(int semid)
  45. {
  46. struct sembuf sops = {0, -1, 0};
  47. int ret;
  48. ret = semop(semid, &sops, 1);
  49. if(ret == -1)
  50. ERR_EXIT("semop");
  51. return 0;
  52. }
  53. int sem_v(int semid)
  54. {
  55. struct sembuf sops = {0, 1, 0};
  56. int ret;
  57. ret = semop(semid, &sops, 1);
  58. if(ret == -1)
  59. ERR_EXIT("semop");
  60. return 0;
  61. }

shmfifo.h

  1. #ifndef SHM_FIFO_H
  2. #define SHM_FIFO_H
  3. #include "ipc.h"
  4. typedef struct shmfifo shmfifo_t;
  5. typedef struct shmhead shmhead_t;
  6. struct shmhead
  7. {
  8. unsigned int blksize; //块大小
  9. unsigned int blocks; //总块数
  10. unsigned int rd_index; //读索引
  11. unsigned int wr_index; //写索引
  12. };
  13. struct shmfifo
  14. {
  15. shmhead_t *p_shm; //共享内存头部指针
  16. char *p_payload; //有效负载的起始地址
  17. int shmid; //共享内存ID
  18. int sem_mutex; //用来互斥用的信号量
  19. int sem_full; //用来控制共享内存是否满的信号量
  20. int sem_empty; //用来控制共享内存是否空的信号量
  21. };
  22. shmfifo_t* shmfifo_init(int key, int blksize, int blocks);
  23. void shmfifo_put(shmfifo_t* fifo, const void* buf);
  24. void shmfifo_get(shmfifo_t* fifo, void* buf);
  25. void shmfifo_destory(shmfifo_t *fifo);
  26. #endif // !SHM_FIFO_H

shmfifo.c

  1. #include "shmfifo.h"
  2. #include <assert.h>
  3. #include <sys/ipc.h>
  4. #include <sys/shm.h>
  5. shmfifo_t* shmfifo_init(int key, int blksize, int blocks)
  6. {
  7. shmfifo_t *fifo = (shmfifo_t*)malloc(sizeof(shmfifo_t));
  8. assert(fifo != NULL);
  9. memset(fifo, 0, sizeof(shmfifo_t));
  10. int shmid;
  11. //假设共享内存已存在,直接打开
  12. shmid = shmget(key, 0, 0);
  13. int size = sizeof(shmhead_t) + blksize*blocks;
  14. if(shmid == -1)
  15. {
  16. //打开失败,表示之前没有创建共享内存
  17. fifo->shmid = shmget(key, size, IPC_CREAT|0666);
  18. if(fifo->shmid == -1)
  19. ERR_EXIT("shmget");
  20. //把共享内存区对象映射到调用进程的地址空间
  21. fifo->p_shm = (shmhead_t*)shmat(fifo->shmid, NULL, 0);
  22. if(fifo->p_shm == (shmhead_t*)-1)
  23. ERR_EXIT("shmat");
  24. //初始化fifo这个结构
  25. fifo->p_payload = (char *)(fifo->p_shm + 1);
  26. fifo->p_shm->blksize = blksize;
  27. fifo->p_shm->blocks = blocks;
  28. fifo->p_shm->rd_index = 0;
  29. fifo->p_shm->wr_index = 0;
  30. //创建信号量
  31. fifo->sem_mutex = sem_create(key);
  32. fifo->sem_full = sem_create(key+1);
  33. fifo->sem_empty = sem_create(key+2);
  34. //设置信号量初始值
  35. sem_setval(fifo->sem_mutex, 1);
  36. sem_setval(fifo->sem_full, blocks);
  37. sem_setval(fifo->sem_empty, 0);
  38. }
  39. else
  40. {
  41. //打开成功,共享内存和信号量已经存在
  42. //共享内存和信号量使用的同一个key;共享内存之间或信号量之间不能用一个key
  43. fifo->shmid = shmid;
  44. fifo->p_shm = shmat(fifo->shmid, NULL, 0);
  45. if(fifo->p_shm == (shmhead_t*)-1)
  46. ERR_EXIT("shmat");
  47. fifo->p_payload = (char *)fifo->p_shm+1;
  48. fifo->sem_mutex = sem_open(key);
  49. fifo->sem_full = sem_open(key+1);
  50. fifo->sem_empty = sem_open(key+2);
  51. }
  52. return fifo;
  53. }
  54. void shmfifo_put(shmfifo_t* fifo, const void* buf)
  55. {
  56. //对信号量sem_full进行P操作;(sem_full = blocks)
  57. //sem_full--
  58. //若sem_full减1后仍大于或等于0,则进程继续执行
  59. //若sem_full减1后小于0,则该进程被阻塞后放入等待该信号量的等待队列中,然后转进程调度
  60. sem_p(fifo->sem_full);
  61. // >=0
  62. //进程对信号量sem_mutex进行P操作,其它写进程将阻塞
  63. sem_p(fifo->sem_mutex);
  64. //将buf拷贝到共享内存中
  65. memcpy(fifo->p_payload + fifo->p_shm->blksize*fifo->p_shm->wr_index, buf, fifo->p_shm->blksize);
  66. //更新写的下标
  67. fifo->p_shm->wr_index = (fifo->p_shm->wr_index+1) % fifo->p_shm->blksize;
  68. //进程对信号量sem_mutex进行V操作,其他写进程可以执行
  69. sem_v(fifo->sem_mutex);
  70. //对共享内存进行V操作;
  71. //sem_empty ++
  72. //若加1后结果大于0,则进程继续执行;
  73. //若相加后结果小于或等于0,则从该信号的等待队列中释放一个等待进程,然后再返回原进程继续执行或转进程调度。
  74. sem_v(fifo->sem_empty);
  75. }
  76. void shmfifo_get(shmfifo_t* fifo, void* buf)
  77. {
  78. //对信号量sem_empty进行P操作;(sem_full = 0)
  79. //sem_empty--
  80. //若sem_empty减1后仍大于或等于0,则进程继续执行
  81. //若sem_empty减1后小于0,则该进程被阻塞后放入等待该信号量的等待队列中,然后转进程调度
  82. sem_p(fifo->sem_empty);
  83. // >=0
  84. //进程对信号量sem_mutex进行P操作,其它读进程将阻塞
  85. sem_p(fifo->sem_mutex);
  86. //将共享内存拷贝到buf中
  87. memcpy( buf, fifo->p_payload + fifo->p_shm->blksize*fifo->p_shm->rd_index, fifo->p_shm->blksize);
  88. //更新读的下标
  89. fifo->p_shm->rd_index = (fifo->p_shm->rd_index+1) % fifo->p_shm->blksize;
  90. //进程对信号量sem_mutex进行V操作,其他写进程可以执行
  91. sem_v(fifo->sem_mutex);
  92. //对共享内存进行V操作;
  93. //sem_full ++
  94. //若加1后结果大于0,则进程继续执行;
  95. //若相加后结果小于或等于0,则从该信号的等待队列中释放一个等待进程,然后再返回原进程继续执行或转进程调度。
  96. sem_v(fifo->sem_full);
  97. }
  98. void shmfifo_destory(shmfifo_t *fifo)
  99. {
  100. sem_del(fifo->sem_mutex);
  101. sem_del(fifo->sem_full);
  102. sem_del(fifo->sem_empty);
  103. shmdt(fifo->p_shm);
  104. shmctl(fifo->shmid, IPC_RMID, NULL);
  105. free(fifo);
  106. }

shmfifo_send.c

  1. #include "shmfifo.h"
  2. typedef struct stu
  3. {
  4. int name[32];
  5. int age;
  6. }STU;
  7. int main(void)
  8. {
  9. shmfifo_t *fifo = shmfifo_init(1234, sizeof(STU), 3);
  10. STU s;
  11. memset(&s, 9, sizeof(STU));
  12. s.name[0] = 'A';
  13. int i;
  14. for(i=0; i<5; ++i)
  15. {
  16. s.age = 20 + i;
  17. shmfifo_put(fifo,&s);
  18. s.name[0] = s.name[0] + 1;
  19. printf("send ok\n");
  20. }
  21. return 0;
  22. }

shmfifo_recv.c

  1. #include "shmfifo.h"
  2. typedef struct stu
  3. {
  4. int name[32];
  5. int age;
  6. }STU;
  7. int main(void)
  8. {
  9. shmfifo_t *fifo = shmfifo_init(1234, sizeof(STU), 3);
  10. STU s;
  11. memset(&s, 9, sizeof(STU));
  12. int i;
  13. for(i=0; i<5; ++i)
  14. {
  15. s.age = 20 + i;
  16. shmfifo_get(fifo,&s);
  17. printf("name = %s age = %d\n",s.name, s.age);
  18. }
  19. return 0;
  20. }

shmfifo_free

  1. #include "shmfifo.h"
  2. typedef struct stu
  3. {
  4. int name[32];
  5. int age;
  6. }STU;
  7. int main(void)
  8. {
  9. shmfifo_t *fifo = shmfifo_init(1234, sizeof(STU), 3);
  10. shmfifo_destory(fifo);
  11. return 0;
  12. }

Makefile

  1. .PHONY:clean all
  2. CC=gcc
  3. CFLAGS=-Wall -g
  4. BIN = shmfifo_recv shmfifo_send shmfifo_free
  5. OBJS1 = shmfifo_recv.o shmfifo.o ipc.o
  6. OBJS2 = shmfifo_send.o shmfifo.o ipc.o
  7. OBJS3 = shmfifo_free.o shmfifo.o ipc.o
  8. all:$(BIN)
  9. %.o:%.c
  10. $(CC) $(CFLAGS) -c $< -o $@
  11. shmfifo_recv: ${OBJS1}
  12. $(CC) $(CFLAGS) $^ -o $@
  13. shmfifo_send: ${OBJS2}
  14. $(CC) $(CFLAGS) $^ -o $@
  15. shmfifo_free: ${OBJS3}
  16. $(CC) $(CFLAGS) $^ -o $@
  17. clean:
  18. rm -rf *.o $(BIN)

第三十三章 System V共享内存与信号量综合的更多相关文章

  1. system v共享内存与信号量综合

    ipc.h #include <sys/types.h> #include <unistd.h> #include <sys/ipc.h> #include < ...

  2. 第二十九章 System V共享内存

    共享内存数据结构 共享内存函数 shmget int shmget(key_t key, size_t size, int shmflg); 功能: 用于创建共享内存 参数: key : 这个共享内存 ...

  3. Linux进程通信之System V共享内存

    前面已经介绍过了POSIX共享内存区,System V共享内存区在概念上类似POSIX共享内存区,POSIX共享内存区的使用是调用shm_open创建共享内存区后调用mmap进行内存区的映射,而Sys ...

  4. UNIX环境高级编程——System V 共享内存区

    共享内存区域是被多个进程共享的一部分物理内存.如果多个进程都把该内存区域映射到自己的虚拟地址空间,则这些进程就都可以直接访问该共享内存区域,从而可以通过该区域进行通信.共享内存是进程间共享数据的一种最 ...

  5. Linux IPC实践(9) --System V共享内存

    共享内存API #include <sys/ipc.h> #include <sys/shm.h> int shmget(key_t key, size_t size, int ...

  6. System V共享内存介绍

    (一)简单概念 共享内存作为一种进程间通信的方式,其相较于其他进程间通信方式而言最大的优点就是数据传输速率快.其内部实现的方式采用了Linux进程地址空间中的mmap文件映射区,将文件内容直接映射到各 ...

  7. 共享内存之——system V共享内存

    System V 的IPC对象有共享内存.消息队列.信号灯(量). 注意:在IPC的通信模式下,不管是共享内存.消息队列还是信号灯,每个IPC的对象都有唯一的名字,称为"键(key)&quo ...

  8. System V共享内存

    目录 1. 概述 2. System V共享内存API shmget shmat shmdt shmctl 3. 简单的程序 代码实现 common.h shmcreate.c shmrmid.c s ...

  9. 阐述linux IPC(五岁以下儿童):system V共享内存

    [版权声明:尊重原创.转载请保留源:blog.csdn.net/shallnet 要么 .../gentleliu,文章学习交流,不用于商业用途]         system V共享内存和posix ...

随机推荐

  1. 防御 DDoS 的终极奥义——又拍云 SCDN

    现如今不论是年轻的 80.90 后,还是 70.60 后,都在享受互联网带来的舒适和便利.在家就可以"逛商场",完全不受时间的限制:在线支付既方便又安全:业余娱乐项目多种多样,打农 ...

  2. 向net core 3.0进击——April.WebApi从2.2爬到3.0

    目录 前言 升级之路 测试 小结 前言 在之前对Swagger的变化做了调整后,就开始想着要不把之前的工程升级得了,这样就还是个demo工程,来做各种测试(当然还是因为懒),这就有了今天这个比较折腾的 ...

  3. ELK 学习笔记之 Logstash之inputs配置

    Logstash之inputs配置: input plugin doc: https://www.elastic.co/guide/en/logstash/current/index.html 插件很 ...

  4. 用js做数字字母混合的随机四位验证码

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  5. 网络驱动之net_device结构体

    在Linux系统中,网络设备都被抽象为struct net_device结构体.它是网络设备硬件与上层协议之间联系的接口,了解它对编写网络驱动程序非常有益,所以本文将着手简要介绍linux-2.6.3 ...

  6. spring源码分析系列5:ApplicationContext的初始化与Bean生命周期

    回顾Bean与BeanDefinition的关系. BeanFactory容器. ApplicationContext上下文. 首先总结下: 开发人员定义Bean信息:分为XML形式定义:注解式定义 ...

  7. .NET Core 3.0 ,WTM 2.3.9发布

    .Net Core 3.0已经来了,WTM怎么可以落后呢.最新发布的WTM2.3.9版本已经支持.Net Core 3.0啦,现在在线生成项目的时候可以选择2.2和3.0两个版本.小伙伴们快来体验吧. ...

  8. Bran的内核开发教程(bkerndev)-02 准备工作

    准备工作   内核开发是编写代码以及调试各种系统组件的漫长过程.一开始这似乎是一个让人畏惧的任务,但是并不需要大量的工具集来编写自己的内核.这个内核开发教程主要涉及使用GRUB将内核加载到内存中.GR ...

  9. Bran的内核开发教程(bkerndev)-01 介绍

    介绍   内核开发不是件容易的事,这是对一个程序员编程能力的考验.开发内核其实就是开发一个能够与硬件交互和管理硬件的软件.内核也是一个操作系统的核心,是管理硬件资源的逻辑.   处理器或是CPU是内核 ...

  10. Jsoup-解析HTML工具(简单爬虫工具)

    Jsoup-解析HTML工具(简单爬虫工具) 一.简介 ​ jsoup 是一款Java 的HTML解析器,可直接解析某个URL地址.HTML文本内容.它提供了一套非常省力的API,可通过DOM,CSS ...