[关闭]
@codejan 2018-11-13T12:44:33.000000Z 字数 5014 阅读 1702

实验报告_生产者消费者问题

操作系统


姓名:唐鉴恒 专业:数学与应用数学(基地) 学号:1507402086 日期:2017.10.1


一. 题目

利用信号量机制, 实现生产者与消费者问题.

二. 方案设计

1)背景知识

2)解题思路

通过设置fullBuffer, emptyBuffer信号量解决生产者-消费着问题. 如果把fullBuffer和mutex的P操作顺序互换, 可能会引起死锁.
伪代码如下:

  1. Class BoundedBudder {
  2. mutex = new Semaphore(1);
  3. fullBuffer = new Semaphore(0);
  4. emptyBuffer = new Semphore(n);
  5. }
  6. BoundedBudder::Producer(c) {
  7. emptyBuffer->P();
  8. mutex->P();
  9. add c to the buffer;
  10. mutex->V();
  11. fullBuffer->V();
  12. }
  13. BoundedBudder::Consumer(c) {
  14. fullBuffer->P();
  15. mutex->P();
  16. remove c from the buffer;
  17. mutex->V();
  18. emptyBuffer->V();
  19. }

3)具体实现

源代码pv.hpv.c实现P,V操作, 其他程序使用#include<pv.h>调用.

源代码producter.c先获取信号量和共享内存, 设置共享缓冲区. 然后模拟生产者的行为, 每次生产一个随机数存放在缓冲区, 总共打印 20 次, 每次延迟一秒.

源代码 consumer.c 先获取信号量和共享内存, 设置共享缓冲区. 然后模拟消费者的行为, 每次从缓冲区中取出一个数打印, 总共取 20 次, 每次延迟一秒.

空文件 file_for_key 被用于产生、获取信号量和共享内存.

利用makefile指定编译顺序

三. 运行结果与分析

运行 make 之后, 得到三个可执行文件 sem_init, producter, consumer. 运行make clean可以清除这三个文件
在终端中先运行 sem_init, 然后在新开的终端上运行 producterconsumer, 通过观察各个终端上的输
出, 可以判断是否符合预期.

DeepinScreenshot_select-area_20171007131523.png-96.5kB

DeepinScreenshot_select-area_20171007131459.png-87.2kB

DeepinScreenshot_select-area_20171007131449.png-55.9kB

四. 源代码

pv.h

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <sys/types.h>
  5. #include <sys/ipc.h>
  6. #include <sys/sem.h>
  7. #include <sys/shm.h>
  8. #define BUFFER_SIZE 10
  9. #define SHM_SIZE 102
  10. #define PRODUCT_NUM 25
  11. void
  12. P (int sem_id);
  13. void
  14. V (int sem_id);

pv.c

  1. #include "pv.h"
  2. void
  3. P (int sem_id)
  4. {
  5. struct sembuf semop_buf;
  6. semop_buf.sem_num = 0;
  7. semop_buf.sem_op = -1;
  8. semop_buf.sem_flg = 0;
  9. if (semop (sem_id, &semop_buf, 1) == -1)
  10. {
  11. perror ("PP"); //perror - print a system error message
  12. exit (0);
  13. }
  14. }
  15. void
  16. V (int sem_id)
  17. {
  18. struct sembuf semop_buf;
  19. semop_buf.sem_num = 0;
  20. semop_buf.sem_op = 1;
  21. semop_buf.sem_flg = 0;
  22. if (semop (sem_id, &semop_buf, 1) == -1)
  23. {
  24. perror ("VV");
  25. exit (0);
  26. }
  27. }
  28. void
  29. showval (int sem_a, int sem_b)
  30. {
  31. int val_a, val_b;
  32. val_a = semctl (sem_a, 0, GETVAL);
  33. val_b = semctl (sem_b, 0, GETVAL);
  34. printf ("process %d: %d %d\n", getpid (), val_a, val_b);
  35. if (val_a == 1 && val_b == 1)
  36. exit (0);
  37. }

producer.c

  1. #include "pv.h"
  2. int
  3. main ()
  4. {
  5. int sem_empty, sem_full;
  6. key_t key[2];
  7. //ftok - convert a pathname and a project identifier to a System V IPC key
  8. key[0] = ftok ("file_for_key", 1);
  9. key[1] = ftok ("file_for_key", 2);
  10. printf ("key: %x %x\n", key[0], key[1]);
  11. /*
  12. semget - get a System V semaphore set identifier
  13. RETURN VALUE
  14. If successful, the return value will be the semaphore set identifier (a non‐
  15. negative integer), otherwise, -1 is returned, with errno indicating the
  16. error.
  17. */
  18. sem_empty = semget (key[0], 0, 0);
  19. sem_full = semget (key[1], 0, 0);
  20. if (sem_empty < 0 || sem_full < 0)
  21. {
  22. printf ("There are not sem_empty or sem_full!\n");
  23. exit(1);
  24. }
  25. int shm_id = shmget (key[0], 0, 0);
  26. if (shm_id)
  27. printf ("shm id is %d\n", shm_id);
  28. else
  29. {
  30. printf ("Key %d have not SHARE MEMORY!\n", key[0]);
  31. exit(1);
  32. }
  33. int *buffer;
  34. int *in;
  35. int *out;
  36. /*
  37. shmat, shmdt - System V shared memory operations
  38. RETURN VALUE
  39. On success, shmat() returns the address of the attached shared memory seg‐
  40. ment; on error, (void *) -1 is returned, and errno is set to indicate the
  41. cause of the error.
  42. */
  43. in = (int *) shmat(shm_id, NULL, 0);
  44. out = in + 1;
  45. buffer = out + 1;
  46. int i = 0;
  47. /*
  48. producer的过程:
  49. 1. 对信号量sem_empty执行P操作
  50. 2. 向缓冲区中in指针的位置放入一个随机数并打印
  51. 3. 把in指针向前移动一个单位
  52. 4. 对信号量sem_full执行V操作
  53. 5. 计数器加1
  54. 6. 如此往复, 直到生产完成指定数量为止
  55. */
  56. while (1)
  57. {
  58. P(sem_empty);
  59. buffer[*in] = random() % 1000;
  60. printf ("%d\n", buffer[*in]);
  61. *in = (*in + 1) % BUFFER_SIZE;
  62. V(sem_full);
  63. i++;
  64. if (i > PRODUCT_NUM)
  65. break;
  66. }
  67. return 0;
  68. }

consumer.c

  1. #include "pv.h"
  2. int
  3. main ()
  4. {
  5. int sem_empty, sem_full;
  6. key_t key[2];
  7. //ftok - convert a pathname and a project identifier to a System V IPC key
  8. key[0] = ftok ("file_for_key", 1);
  9. key[1] = ftok ("file_for_key", 2);
  10. printf ("key: %x %x\n", key[0], key[1]);
  11. /*
  12. semget - get a System V semaphore set identifier
  13. RETURN VALUE
  14. If successful, the return value will be the semaphore set identifier (a non‐
  15. negative integer), otherwise, -1 is returned, with errno indicating the
  16. error.
  17. */
  18. sem_empty = semget (key[0], 0, 0);
  19. sem_full = semget (key[1], 0, 0);
  20. if (sem_empty < 0 || sem_full < 0)
  21. {
  22. printf ("There are not sem_empty or sem_full!\n");
  23. exit(1);
  24. }
  25. int shm_id = shmget (key[0], 0, 0);
  26. if (shm_id)
  27. printf ("shm id is %d\n", shm_id);
  28. else
  29. {
  30. printf ("Key %d have not SHARE MEMORY!\n", key[0]);
  31. exit(1);
  32. }
  33. int *buffer;
  34. int *in;
  35. int *out;
  36. /*
  37. shmat, shmdt - System V shared memory operations
  38. RETURN VALUE
  39. On success, shmat() returns the address of the attached shared memory seg‐
  40. ment; on error, (void *) -1 is returned, and errno is set to indicate the
  41. cause of the error.
  42. */
  43. in = (int *) shmat(shm_id, NULL, 0);
  44. out = in + 1;
  45. buffer = out + 1;
  46. int i = 0;
  47. /*
  48. producer的过程:
  49. 1. 对信号量sem_empty执行P操作
  50. 2. 向缓冲区中in指针的位置放入一个随机数并打印
  51. 3. 把in指针向前移动一个单位
  52. 4. 对信号量sem_full执行V操作
  53. 5. 计数器加1
  54. 6. 如此往复, 直到生产完成指定数量为止
  55. */
  56. while (1)
  57. {
  58. P(sem_empty);
  59. buffer[*in] = random() % 1000;
  60. printf ("%d\n", buffer[*in]);
  61. *in = (*in + 1) % BUFFER_SIZE;
  62. V(sem_full);
  63. i++;
  64. if (i > PRODUCT_NUM)
  65. break;
  66. }
  67. return 0;
  68. }

makefile

  1. all: sem_init producer consumer
  2. pv.o: pv.c
  3. gcc -Wall -O2 -c pv.c
  4. sem_init: sem_init.c
  5. gcc -Wall -O2 sem_init.c -o sem_init
  6. producer: producer.c pv.o
  7. gcc -Wall -O2 producer.c pv.o -o producer
  8. consumer: consumer.c pv.o
  9. gcc -Wall -O2 consumer.c pv.o -o consumer
  10. clean:
  11. rm -f pv.o sem_init producer consumer \
  12. sem_init.c~ producer.c~ consumer.c~ pv.c~ pv.h~
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注